LCOV - code coverage report
Current view: top level - layout/painting - FrameLayerBuilder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1750 2573 68.0 %
Date: 2017-07-14 16:53:18 Functions: 155 211 73.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/DebugOnly.h"
       7             : 
       8             : #include "FrameLayerBuilder.h"
       9             : 
      10             : #include "gfxContext.h"
      11             : #include "mozilla/LookAndFeel.h"
      12             : #include "mozilla/Maybe.h"
      13             : #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
      14             : #include "mozilla/gfx/Matrix.h"
      15             : #include "ActiveLayerTracker.h"
      16             : #include "BasicLayers.h"
      17             : #include "ImageContainer.h"
      18             : #include "ImageLayers.h"
      19             : #include "LayerTreeInvalidation.h"
      20             : #include "Layers.h"
      21             : #include "LayerUserData.h"
      22             : #include "MaskLayerImageCache.h"
      23             : #include "UnitTransforms.h"
      24             : #include "Units.h"
      25             : #include "gfx2DGlue.h"
      26             : #include "gfxEnv.h"
      27             : #include "gfxUtils.h"
      28             : #include "nsAutoPtr.h"
      29             : #include "nsAnimationManager.h"
      30             : #include "nsDisplayList.h"
      31             : #include "nsDocShell.h"
      32             : #include "nsIScrollableFrame.h"
      33             : #include "nsImageFrame.h"
      34             : #include "nsLayoutUtils.h"
      35             : #include "nsPresContext.h"
      36             : #include "nsPrintfCString.h"
      37             : #include "nsSVGIntegrationUtils.h"
      38             : #include "nsTransitionManager.h"
      39             : #include "mozilla/LayerTimelineMarker.h"
      40             : 
      41             : #include "mozilla/EffectCompositor.h"
      42             : #include "mozilla/Move.h"
      43             : #include "mozilla/ReverseIterator.h"
      44             : #include "mozilla/gfx/2D.h"
      45             : #include "mozilla/gfx/Tools.h"
      46             : #include "mozilla/layers/ShadowLayers.h"
      47             : #include "mozilla/layers/TextureClient.h"
      48             : #include "mozilla/layers/TextureWrapperImage.h"
      49             : #include "mozilla/Unused.h"
      50             : #include "GeckoProfiler.h"
      51             : #include "LayersLogging.h"
      52             : #include "gfxPrefs.h"
      53             : 
      54             : #include <algorithm>
      55             : #include <functional>
      56             : 
      57             : using namespace mozilla::layers;
      58             : using namespace mozilla::gfx;
      59             : 
      60             : namespace mozilla {
      61             : 
      62             : class PaintedDisplayItemLayerUserData;
      63             : 
      64             : static nsTHashtable<nsPtrHashKey<DisplayItemData>>* sAliveDisplayItemDatas;
      65             : 
      66             : /**
      67             :  * The address of gPaintedDisplayItemLayerUserData is used as the user
      68             :  * data key for PaintedLayers created by FrameLayerBuilder.
      69             :  * It identifies PaintedLayers used to draw non-layer content, which are
      70             :  * therefore eligible for recycling. We want display items to be able to
      71             :  * create their own dedicated PaintedLayers in BuildLayer, if necessary,
      72             :  * and we wouldn't want to accidentally recycle those.
      73             :  * The user data is a PaintedDisplayItemLayerUserData.
      74             :  */
      75             : uint8_t gPaintedDisplayItemLayerUserData;
      76             : /**
      77             :  * The address of gColorLayerUserData is used as the user
      78             :  * data key for ColorLayers created by FrameLayerBuilder.
      79             :  * The user data is null.
      80             :  */
      81             : uint8_t gColorLayerUserData;
      82             : /**
      83             :  * The address of gImageLayerUserData is used as the user
      84             :  * data key for ImageLayers created by FrameLayerBuilder.
      85             :  * The user data is null.
      86             :  */
      87             : uint8_t gImageLayerUserData;
      88             : /**
      89             :  * The address of gLayerManagerUserData is used as the user
      90             :  * data key for retained LayerManagers managed by FrameLayerBuilder.
      91             :  * The user data is a LayerManagerData.
      92             :  */
      93             : uint8_t gLayerManagerUserData;
      94             : /**
      95             :  * The address of gMaskLayerUserData is used as the user
      96             :  * data key for mask layers managed by FrameLayerBuilder.
      97             :  * The user data is a MaskLayerUserData.
      98             :  */
      99             : uint8_t gMaskLayerUserData;
     100             : /**
     101             :  * The address of gCSSMaskLayerUserData is used as the user
     102             :  * data key for mask layers of css masking managed by FrameLayerBuilder.
     103             :  * The user data is a CSSMaskLayerUserData.
     104             :  */
     105             : uint8_t gCSSMaskLayerUserData;
     106             : 
     107             : // a global cache of image containers used for mask layers
     108             : static MaskLayerImageCache* gMaskLayerImageCache = nullptr;
     109             : 
     110         261 : static inline MaskLayerImageCache* GetMaskLayerImageCache()
     111             : {
     112         261 :   if (!gMaskLayerImageCache) {
     113           2 :     gMaskLayerImageCache = new MaskLayerImageCache();
     114             :   }
     115             : 
     116         261 :   return gMaskLayerImageCache;
     117             : }
     118             : 
     119         187 : FrameLayerBuilder::FrameLayerBuilder()
     120             :   : mRetainingManager(nullptr)
     121             :   , mContainingPaintedLayer(nullptr)
     122             :   , mInactiveLayerClip(nullptr)
     123             :   , mDetectedDOMModification(false)
     124             :   , mInvalidateAllLayers(false)
     125             :   , mInLayerTreeCompressionMode(false)
     126             :   , mContainerLayerGeneration(0)
     127         187 :   , mMaxContainerLayerGeneration(0)
     128             : {
     129         187 :   MOZ_COUNT_CTOR(FrameLayerBuilder);
     130         187 : }
     131             : 
     132         561 : FrameLayerBuilder::~FrameLayerBuilder()
     133             : {
     134         187 :   GetMaskLayerImageCache()->Sweep();
     135         187 :   MOZ_COUNT_DTOR(FrameLayerBuilder);
     136         561 : }
     137             : 
     138          87 : DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey,
     139          87 :                                  Layer* aLayer, nsIFrame* aFrame)
     140             : 
     141             :   : mRefCnt(0)
     142             :   , mParent(aParent)
     143             :   , mLayer(aLayer)
     144             :   , mDisplayItemKey(aKey)
     145             :   , mItem(nullptr)
     146             :   , mUsed(true)
     147          87 :   , mIsInvalid(false)
     148             : {
     149          87 :   MOZ_COUNT_CTOR(DisplayItemData);
     150             : 
     151          87 :   if (!sAliveDisplayItemDatas) {
     152           2 :     sAliveDisplayItemDatas = new nsTHashtable<nsPtrHashKey<DisplayItemData>>();
     153             :   }
     154          87 :   MOZ_RELEASE_ASSERT(!sAliveDisplayItemDatas->Contains(this));
     155          87 :   sAliveDisplayItemDatas->PutEntry(this);
     156             : 
     157          87 :   MOZ_RELEASE_ASSERT(mLayer);
     158          87 :   if (aFrame) {
     159           2 :     AddFrame(aFrame);
     160             :   }
     161             : 
     162          87 : }
     163             : 
     164             : void
     165          87 : DisplayItemData::AddFrame(nsIFrame* aFrame)
     166             : {
     167          87 :   MOZ_RELEASE_ASSERT(mLayer);
     168          87 :   mFrameList.AppendElement(aFrame);
     169             : 
     170          87 :   SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
     171          87 :   array.AppendElement(this);
     172          87 : }
     173             : 
     174             : void
     175           0 : DisplayItemData::RemoveFrame(nsIFrame* aFrame)
     176             : {
     177           0 :   MOZ_RELEASE_ASSERT(mLayer);
     178           0 :   bool result = mFrameList.RemoveElement(aFrame);
     179           0 :   MOZ_RELEASE_ASSERT(result, "Can't remove a frame that wasn't added!");
     180             : 
     181           0 :   SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
     182           0 :   array.RemoveElement(this);
     183           0 : }
     184             : 
     185             : void
     186        1459 : DisplayItemData::EndUpdate()
     187             : {
     188        1459 :   MOZ_RELEASE_ASSERT(mLayer);
     189        1459 :   MOZ_ASSERT(!mItem);
     190        1459 :   mIsInvalid = false;
     191        1459 :   mUsed = false;
     192        1459 : }
     193             : 
     194             : void
     195        1237 : DisplayItemData::EndUpdate(nsAutoPtr<nsDisplayItemGeometry> aGeometry)
     196             : {
     197        1237 :   MOZ_RELEASE_ASSERT(mLayer);
     198        1237 :   MOZ_ASSERT(mItem);
     199        1237 :   MOZ_ASSERT(mGeometry || aGeometry);
     200             : 
     201        1237 :   if (aGeometry) {
     202         300 :     mGeometry = aGeometry;
     203             :   }
     204        1237 :   mClip = mItem->GetClip();
     205        1237 :   mChangedFrameInvalidations.SetEmpty();
     206             : 
     207        1237 :   mItem = nullptr;
     208        1237 :   EndUpdate();
     209        1237 : }
     210             : 
     211             : void
     212        1459 : DisplayItemData::BeginUpdate(Layer* aLayer, LayerState aState,
     213             :                              uint32_t aContainerLayerGeneration,
     214             :                              nsDisplayItem* aItem /* = nullptr */)
     215             : {
     216        1459 :   MOZ_RELEASE_ASSERT(mLayer);
     217        1459 :   MOZ_RELEASE_ASSERT(aLayer);
     218        1459 :   mLayer = aLayer;
     219        1459 :   mOptLayer = nullptr;
     220        1459 :   mInactiveManager = nullptr;
     221        1459 :   mLayerState = aState;
     222        1459 :   mContainerLayerGeneration = aContainerLayerGeneration;
     223        1459 :   mUsed = true;
     224             : 
     225        1459 :   if (aLayer->AsPaintedLayer()) {
     226        1240 :     mItem = aItem;
     227             :   }
     228             : 
     229        1459 :   if (!aItem) {
     230          26 :     return;
     231             :   }
     232             : 
     233             :   // We avoid adding or removing element unnecessarily
     234             :   // since we have to modify userdata each time
     235        2866 :   AutoTArray<nsIFrame*, 4> copy(mFrameList);
     236        1433 :   if (!copy.RemoveElement(aItem->Frame())) {
     237          85 :     AddFrame(aItem->Frame());
     238             :     mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
     239          85 :                                   aItem->Frame()->GetVisualOverflowRect());
     240             :   }
     241             : 
     242        2866 :   AutoTArray<nsIFrame*,4> mergedFrames;
     243        1433 :   aItem->GetMergedFrames(&mergedFrames);
     244        1433 :   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
     245           0 :     if (!copy.RemoveElement(mergedFrames[i])) {
     246           0 :       AddFrame(mergedFrames[i]);
     247             :       mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
     248           0 :                                     mergedFrames[i]->GetVisualOverflowRect());
     249             :     }
     250             :   }
     251             : 
     252        1433 :   for (uint32_t i = 0; i < copy.Length(); i++) {
     253           0 :     RemoveFrame(copy[i]);
     254             :     mChangedFrameInvalidations.Or(mChangedFrameInvalidations,
     255           0 :                                   copy[i]->GetVisualOverflowRect());
     256             :   }
     257             : }
     258             : 
     259             : static const nsIFrame* sDestroyedFrame = nullptr;
     260          50 : DisplayItemData::~DisplayItemData()
     261             : {
     262          25 :   MOZ_COUNT_DTOR(DisplayItemData);
     263          25 :   MOZ_RELEASE_ASSERT(mLayer);
     264          50 :   for (uint32_t i = 0; i < mFrameList.Length(); i++) {
     265          25 :     nsIFrame* frame = mFrameList[i];
     266          25 :     if (frame == sDestroyedFrame) {
     267          12 :       continue;
     268             :     }
     269          13 :     SmallPointerArray<DisplayItemData>& array = frame->DisplayItemData();
     270          13 :     array.RemoveElement(this);
     271             :   }
     272             : 
     273          25 :   MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas);
     274             :   nsPtrHashKey<mozilla::DisplayItemData>* entry
     275          25 :     = sAliveDisplayItemDatas->GetEntry(this);
     276          25 :   MOZ_RELEASE_ASSERT(entry);
     277             : 
     278          25 :   sAliveDisplayItemDatas->RemoveEntry(entry);
     279             : 
     280          25 :   if (sAliveDisplayItemDatas->Count() == 0) {
     281           0 :     delete sAliveDisplayItemDatas;
     282           0 :     sAliveDisplayItemDatas = nullptr;
     283             :   }
     284          25 : }
     285             : 
     286             : void
     287           9 : DisplayItemData::ClearAnimationCompositorState()
     288             : {
     289          18 :   if (mDisplayItemKey != nsDisplayItem::TYPE_TRANSFORM &&
     290           9 :       mDisplayItemKey != nsDisplayItem::TYPE_OPACITY) {
     291           7 :     return;
     292             :   }
     293             : 
     294           4 :   for (nsIFrame* frame : mFrameList) {
     295           2 :     nsCSSPropertyID prop = mDisplayItemKey == nsDisplayItem::TYPE_TRANSFORM ?
     296           2 :       eCSSProperty_transform : eCSSProperty_opacity;
     297           2 :     EffectCompositor::ClearIsRunningOnCompositor(frame, prop);
     298             :   }
     299             : }
     300             : 
     301             : const nsRegion&
     302        1109 : DisplayItemData::GetChangedFrameInvalidations()
     303             : {
     304        1109 :   return mChangedFrameInvalidations;
     305             : }
     306             : 
     307             : DisplayItemData*
     308        6518 : DisplayItemData::AssertDisplayItemData(DisplayItemData* aData)
     309             : {
     310        6518 :   MOZ_RELEASE_ASSERT(aData);
     311        6518 :   MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas && sAliveDisplayItemDatas->Contains(aData));
     312        6518 :   MOZ_RELEASE_ASSERT(aData->mLayer);
     313        6518 :   return aData;
     314             : }
     315             : 
     316             : /**
     317             :  * This is the userdata we associate with a layer manager.
     318             :  */
     319             : class LayerManagerData : public LayerUserData {
     320             : public:
     321          12 :   explicit LayerManagerData(LayerManager *aManager)
     322          12 :     : mLayerManager(aManager)
     323             : #ifdef DEBUG_DISPLAY_ITEM_DATA
     324             :     , mParent(nullptr)
     325             : #endif
     326          12 :     , mInvalidateAllLayers(false)
     327             :   {
     328          12 :     MOZ_COUNT_CTOR(LayerManagerData);
     329          12 :   }
     330          12 :   ~LayerManagerData() {
     331           4 :     MOZ_COUNT_DTOR(LayerManagerData);
     332          12 :   }
     333             : 
     334             : #ifdef DEBUG_DISPLAY_ITEM_DATA
     335             :   void Dump(const char *aPrefix = "") {
     336             :     printf_stderr("%sLayerManagerData %p\n", aPrefix, this);
     337             : 
     338             :     for (auto iter = mDisplayItems.Iter(); !iter.Done(); iter.Next()) {
     339             :       FrameLayerBuilder::DisplayItemData* data = iter.Get()->GetKey();
     340             : 
     341             :       nsAutoCString prefix;
     342             :       prefix += aPrefix;
     343             :       prefix += "  ";
     344             : 
     345             :       const char* layerState;
     346             :       switch (data->mLayerState) {
     347             :       case LAYER_NONE:
     348             :         layerState = "LAYER_NONE"; break;
     349             :       case LAYER_INACTIVE:
     350             :         layerState = "LAYER_INACTIVE"; break;
     351             :       case LAYER_ACTIVE:
     352             :         layerState = "LAYER_ACTIVE"; break;
     353             :       case LAYER_ACTIVE_FORCE:
     354             :         layerState = "LAYER_ACTIVE_FORCE"; break;
     355             :       case LAYER_ACTIVE_EMPTY:
     356             :         layerState = "LAYER_ACTIVE_EMPTY"; break;
     357             :       case LAYER_SVG_EFFECTS:
     358             :         layerState = "LAYER_SVG_EFFECTS"; break;
     359             :       }
     360             :       uint32_t mask = (1 << nsDisplayItem::TYPE_BITS) - 1;
     361             : 
     362             :       nsAutoCString str;
     363             :       str += prefix;
     364             :       str += nsPrintfCString("Frame %p ", data->mFrameList[0]);
     365             :       str += nsDisplayItem::DisplayItemTypeName(static_cast<nsDisplayItem::Type>(data->mDisplayItemKey & mask));
     366             :       if ((data->mDisplayItemKey >> nsDisplayItem::TYPE_BITS)) {
     367             :         str += nsPrintfCString("(%i)", data->mDisplayItemKey >> nsDisplayItem::TYPE_BITS);
     368             :       }
     369             :       str += nsPrintfCString(", %s, Layer %p", layerState, data->mLayer.get());
     370             :       if (data->mOptLayer) {
     371             :         str += nsPrintfCString(", OptLayer %p", data->mOptLayer.get());
     372             :       }
     373             :       if (data->mInactiveManager) {
     374             :         str += nsPrintfCString(", InactiveLayerManager %p", data->mInactiveManager.get());
     375             :       }
     376             :       str += "\n";
     377             : 
     378             :       printf_stderr("%s", str.get());
     379             : 
     380             :       if (data->mInactiveManager) {
     381             :         prefix += "  ";
     382             :         printf_stderr("%sDumping inactive layer info:\n", prefix.get());
     383             :         LayerManagerData* lmd = static_cast<LayerManagerData*>
     384             :           (data->mInactiveManager->GetUserData(&gLayerManagerUserData));
     385             :         lmd->Dump(prefix.get());
     386             :       }
     387             :     }
     388             :   }
     389             : #endif
     390             : 
     391             :   /**
     392             :    * Tracks which frames have layers associated with them.
     393             :    */
     394             :   LayerManager *mLayerManager;
     395             : #ifdef DEBUG_DISPLAY_ITEM_DATA
     396             :   LayerManagerData *mParent;
     397             : #endif
     398             :   nsTHashtable<nsRefPtrHashKey<DisplayItemData> > mDisplayItems;
     399             :   bool mInvalidateAllLayers;
     400             : };
     401             : 
     402             : /* static */ void
     403           0 : FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame)
     404             : {
     405           0 :   RemoveFrameFromLayerManager(aFrame, aFrame->DisplayItemData());
     406           0 :   aFrame->DisplayItemData().Clear();
     407           0 : }
     408             : 
     409        3894 : struct AssignedDisplayItem
     410             : {
     411        1298 :   AssignedDisplayItem(nsDisplayItem* aItem,
     412             :                       const DisplayItemClip& aClip,
     413             :                       LayerState aLayerState)
     414        1298 :     : mItem(aItem)
     415             :     , mClip(aClip)
     416        1298 :     , mLayerState(aLayerState)
     417        1298 :   {}
     418             : 
     419             :   nsDisplayItem* mItem;
     420             :   DisplayItemClip mClip;
     421             :   LayerState mLayerState;
     422             : };
     423             : 
     424             : /**
     425             :  * We keep a stack of these to represent the PaintedLayers that are
     426             :  * currently available to have display items added to.
     427             :  * We use a stack here because as much as possible we want to
     428             :  * assign display items to existing PaintedLayers, and to the lowest
     429             :  * PaintedLayer in z-order. This reduces the number of layers and
     430             :  * makes it more likely a display item will be rendered to an opaque
     431             :  * layer, giving us the best chance of getting subpixel AA.
     432             :  */
     433         774 : class PaintedLayerData {
     434             : public:
     435         258 :   PaintedLayerData() :
     436             :     mAnimatedGeometryRoot(nullptr),
     437             :     mASR(nullptr),
     438             :     mReferenceFrame(nullptr),
     439             :     mLayer(nullptr),
     440             :     mSolidColor(NS_RGBA(0, 0, 0, 0)),
     441             :     mIsSolidColorInVisibleRegion(false),
     442             :     mFontSmoothingBackgroundColor(NS_RGBA(0,0,0,0)),
     443             :     mNeedComponentAlpha(false),
     444             :     mForceTransparentSurface(false),
     445             :     mHideAllLayersBelow(false),
     446             :     mOpaqueForAnimatedGeometryRootParent(false),
     447             :     mDisableFlattening(false),
     448             :     mBackfaceHidden(false),
     449             :     mImage(nullptr),
     450             :     mCommonClipCount(-1),
     451         258 :     mNewChildLayersIndex(-1)
     452         258 :   {}
     453             : 
     454             : #ifdef MOZ_DUMP_PAINTING
     455             :   /**
     456             :    * Keep track of important decisions for debugging.
     457             :    */
     458             :   nsCString mLog;
     459             : 
     460             :   #define FLB_LOG_PAINTED_LAYER_DECISION(pld, ...) \
     461             :           if (gfxPrefs::LayersDumpDecision()) { \
     462             :             pld->mLog.AppendPrintf("\t\t\t\t"); \
     463             :             pld->mLog.AppendPrintf(__VA_ARGS__); \
     464             :           }
     465             : #else
     466             :   #define FLB_LOG_PAINTED_LAYER_DECISION(...)
     467             : #endif
     468             : 
     469             :   /**
     470             :    * Record that an item has been added to the PaintedLayer, so we
     471             :    * need to update our regions.
     472             :    * @param aVisibleRect the area of the item that's visible
     473             :    * @param aSolidColor if non-null, the visible area of the item is
     474             :    * a constant color given by *aSolidColor
     475             :    */
     476             :   void Accumulate(ContainerState* aState,
     477             :                   nsDisplayItem* aItem,
     478             :                   const nsIntRegion& aClippedOpaqueRegion,
     479             :                   const nsIntRect& aVisibleRect,
     480             :                   const DisplayItemClip& aClip,
     481             :                   LayerState aLayerState);
     482             :   AnimatedGeometryRoot* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
     483             : 
     484             :   /**
     485             :    * A region including the horizontal pan, vertical pan, and no action regions.
     486             :    */
     487             :   nsRegion CombinedTouchActionRegion();
     488             : 
     489             :   /**
     490             :    * Add the given hit regions to the hit regions to the hit retions for this
     491             :    * PaintedLayer.
     492             :    */
     493             :   void AccumulateEventRegions(ContainerState* aState, nsDisplayLayerEventRegions* aEventRegions);
     494             : 
     495             :   /**
     496             :    * If this represents only a nsDisplayImage, and the image type supports being
     497             :    * optimized to an ImageLayer, returns true.
     498             :    */
     499             :   bool CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
     500             : 
     501             :   /**
     502             :    * If this represents only a nsDisplayImage, and the image type supports being
     503             :    * optimized to an ImageLayer, returns an ImageContainer for the underlying
     504             :    * image if one is available.
     505             :    */
     506             :   already_AddRefed<ImageContainer> GetContainerForImageLayer(nsDisplayListBuilder* aBuilder);
     507             : 
     508          76 :   bool VisibleAboveRegionIntersects(const nsIntRegion& aRegion) const
     509          76 :   { return !mVisibleAboveRegion.Intersect(aRegion).IsEmpty(); }
     510          63 :   bool VisibleRegionIntersects(const nsIntRegion& aRegion) const
     511          63 :   { return !mVisibleRegion.Intersect(aRegion).IsEmpty(); }
     512             : 
     513             :   /**
     514             :    * The region of visible content in the layer, relative to the
     515             :    * container layer (which is at the snapped top-left of the display
     516             :    * list reference frame).
     517             :    */
     518             :   nsIntRegion  mVisibleRegion;
     519             :   /**
     520             :    * The region of visible content in the layer that is opaque.
     521             :    * Same coordinate system as mVisibleRegion.
     522             :    */
     523             :   nsIntRegion  mOpaqueRegion;
     524             :   /**
     525             :    * The definitely-hit region for this PaintedLayer.
     526             :    */
     527             :   nsRegion  mHitRegion;
     528             :   /**
     529             :    * The maybe-hit region for this PaintedLayer.
     530             :    */
     531             :   nsRegion  mMaybeHitRegion;
     532             :   /**
     533             :    * The dispatch-to-content hit region for this PaintedLayer.
     534             :    */
     535             :   nsRegion  mDispatchToContentHitRegion;
     536             :   /**
     537             :    * The region for this PaintedLayer that is sensitive to events
     538             :    * but disallows panning and zooming. This is an approximation
     539             :    * and any deviation from the true region will be part of the
     540             :    * mDispatchToContentHitRegion.
     541             :    */
     542             :   nsRegion mNoActionRegion;
     543             :   /**
     544             :    * The region for this PaintedLayer that is sensitive to events and
     545             :    * allows horizontal panning but not zooming. This is an approximation
     546             :    * and any deviation from the true region will be part of the
     547             :    * mDispatchToContentHitRegion.
     548             :    */
     549             :   nsRegion mHorizontalPanRegion;
     550             :   /**
     551             :    * The region for this PaintedLayer that is sensitive to events and
     552             :    * allows vertical panning but not zooming. This is an approximation
     553             :    * and any deviation from the true region will be part of the
     554             :    * mDispatchToContentHitRegion.
     555             :    */
     556             :   nsRegion mVerticalPanRegion;
     557             :   /**
     558             :    * Scaled versions of the bounds of mHitRegion and mMaybeHitRegion.
     559             :    * We store these because FindPaintedLayerFor() needs to consume them
     560             :    * in this form, and it's a hot code path so we don't want to scale
     561             :    * them inside that function.
     562             :    */
     563             :   nsIntRect mScaledHitRegionBounds;
     564             :   nsIntRect mScaledMaybeHitRegionBounds;
     565             :   /**
     566             :    * The "active scrolled root" for all content in the layer. Must
     567             :    * be non-null; all content in a PaintedLayer must have the same
     568             :    * active scrolled root.
     569             :    */
     570             :   AnimatedGeometryRoot* mAnimatedGeometryRoot;
     571             :   const ActiveScrolledRoot* mASR;
     572             :   /**
     573             :    * The chain of clips that should apply to this layer.
     574             :    */
     575             :   const DisplayItemClipChain* mClipChain;
     576             :   /**
     577             :    * The offset between mAnimatedGeometryRoot and the reference frame.
     578             :    */
     579             :   nsPoint mAnimatedGeometryRootOffset;
     580             :   /**
     581             :    * If non-null, the frame from which we'll extract "fixed positioning"
     582             :    * metadata for this layer. This can be a position:fixed frame or a viewport
     583             :    * frame; the latter case is used for background-attachment:fixed content.
     584             :    */
     585             :   const nsIFrame* mReferenceFrame;
     586             :   PaintedLayer* mLayer;
     587             :   /**
     588             :    * If mIsSolidColorInVisibleRegion is true, this is the color of the visible
     589             :    * region.
     590             :    */
     591             :   nscolor      mSolidColor;
     592             :   /**
     593             :    * True if every pixel in mVisibleRegion will have color mSolidColor.
     594             :    */
     595             :   bool mIsSolidColorInVisibleRegion;
     596             :   /**
     597             :    * The target background color for smoothing fonts that are drawn on top of
     598             :    * transparent parts of the layer.
     599             :    */
     600             :   nscolor mFontSmoothingBackgroundColor;
     601             :   /**
     602             :    * True if there is any text visible in the layer that's over
     603             :    * transparent pixels in the layer.
     604             :    */
     605             :   bool mNeedComponentAlpha;
     606             :   /**
     607             :    * Set if the layer should be treated as transparent, even if its entire
     608             :    * area is covered by opaque display items. For example, this needs to
     609             :    * be set if something is going to "punch holes" in the layer by clearing
     610             :    * part of its surface.
     611             :    */
     612             :   bool mForceTransparentSurface;
     613             :   /**
     614             :    * Set if all layers below this PaintedLayer should be hidden.
     615             :    */
     616             :   bool mHideAllLayersBelow;
     617             :   /**
     618             :    * Set if the opaque region for this layer can be applied to the parent
     619             :    * animated geometry root of this layer's animated geometry root.
     620             :    * We set this when a PaintedLayer's animated geometry root is a scrollframe
     621             :    * and the PaintedLayer completely fills the displayport of the scrollframe.
     622             :    */
     623             :   bool mOpaqueForAnimatedGeometryRootParent;
     624             :   /**
     625             :    * Set if there is content in the layer that must avoid being flattened.
     626             :    */
     627             :   bool mDisableFlattening;
     628             :   /**
     629             :    * Set if the backface of this region is hidden to the user.
     630             :    * Content that backface is hidden should not be draw on the layer
     631             :    * with visible backface.
     632             :    */
     633             :   bool mBackfaceHidden;
     634             :   /**
     635             :    * Stores the pointer to the nsDisplayImage if we want to
     636             :    * convert this to an ImageLayer.
     637             :    */
     638             :   nsDisplayImageContainer* mImage;
     639             :   /**
     640             :    * Stores the clip that we need to apply to the image or, if there is no
     641             :    * image, a clip for SOME item in the layer. There is no guarantee which
     642             :    * item's clip will be stored here and mItemClip should not be used to clip
     643             :    * the whole layer - only some part of the clip should be used, as determined
     644             :    * by PaintedDisplayItemLayerUserData::GetCommonClipCount() - which may even be
     645             :    * no part at all.
     646             :    */
     647             :   DisplayItemClip mItemClip;
     648             :   /**
     649             :    * The first mCommonClipCount rounded rectangle clips are identical for
     650             :    * all items in the layer.
     651             :    * -1 if there are no items in the layer; must be >=0 by the time that this
     652             :    * data is popped from the stack.
     653             :    */
     654             :   int32_t mCommonClipCount;
     655             :   /**
     656             :    * Index of this layer in mNewChildLayers.
     657             :    */
     658             :   int32_t mNewChildLayersIndex;
     659             :   /*
     660             :    * Updates mCommonClipCount by checking for rounded rect clips in common
     661             :    * between the clip on a new item (aCurrentClip) and the common clips
     662             :    * on items already in the layer (the first mCommonClipCount rounded rects
     663             :    * in mItemClip).
     664             :    */
     665             :   void UpdateCommonClipCount(const DisplayItemClip& aCurrentClip);
     666             :   /**
     667             :    * The region of visible content above the layer and below the
     668             :    * next PaintedLayerData currently in the stack, if any.
     669             :    * This is a conservative approximation: it contains the true region.
     670             :    */
     671             :   nsIntRegion mVisibleAboveRegion;
     672             :   /**
     673             :    * All the display items that have been assigned to this painted layer.
     674             :    * These items get added by Accumulate().
     675             :    */
     676             :   nsTArray<AssignedDisplayItem> mAssignedDisplayItems;
     677             : 
     678             : };
     679             : 
     680         592 : struct NewLayerEntry {
     681         592 :   NewLayerEntry()
     682         592 :     : mAnimatedGeometryRoot(nullptr)
     683             :     , mASR(nullptr)
     684             :     , mClipChain(nullptr)
     685             :     , mScrollMetadataASR(nullptr)
     686             :     , mLayerContentsVisibleRect(0, 0, -1, -1)
     687             :     , mLayerState(LAYER_INACTIVE)
     688             :     , mHideAllLayersBelow(false)
     689             :     , mOpaqueForAnimatedGeometryRootParent(false)
     690             :     , mPropagateComponentAlphaFlattening(true)
     691             :     , mUntransformedVisibleRegion(false)
     692         592 :     , mIsFixedToRootScrollFrame(false)
     693         592 :   {}
     694             :   // mLayer is null if the previous entry is for a PaintedLayer that hasn't
     695             :   // been optimized to some other form (yet).
     696             :   RefPtr<Layer> mLayer;
     697             :   AnimatedGeometryRoot* mAnimatedGeometryRoot;
     698             :   const ActiveScrolledRoot* mASR;
     699             :   const DisplayItemClipChain* mClipChain;
     700             :   const ActiveScrolledRoot* mScrollMetadataASR;
     701             :   // If non-null, this ScrollMetadata is set to the be the first ScrollMetadata
     702             :   // on the layer.
     703             :   UniquePtr<ScrollMetadata> mBaseScrollMetadata;
     704             :   // The following are only used for retained layers (for occlusion
     705             :   // culling of those layers). These regions are all relative to the
     706             :   // container reference frame.
     707             :   nsIntRegion mVisibleRegion;
     708             :   nsIntRegion mOpaqueRegion;
     709             :   // This rect is in the layer's own coordinate space. The computed visible
     710             :   // region for the layer cannot extend beyond this rect.
     711             :   nsIntRect mLayerContentsVisibleRect;
     712             :   LayerState mLayerState;
     713             :   bool mHideAllLayersBelow;
     714             :   // When mOpaqueForAnimatedGeometryRootParent is true, the opaque region of
     715             :   // this layer is opaque in the same position even subject to the animation of
     716             :   // geometry of mAnimatedGeometryRoot. For example when mAnimatedGeometryRoot
     717             :   // is a scrolled frame and the scrolled content is opaque everywhere in the
     718             :   // displayport, we can set this flag.
     719             :   // When this flag is set, we can treat this opaque region as covering
     720             :   // content whose animated geometry root is the animated geometry root for
     721             :   // mAnimatedGeometryRoot->GetParent().
     722             :   bool mOpaqueForAnimatedGeometryRootParent;
     723             : 
     724             :   // If true, then the content flags for this layer should contribute
     725             :   // to our decision to flatten component alpha layers, false otherwise.
     726             :   bool mPropagateComponentAlphaFlattening;
     727             :   // mVisibleRegion is relative to the associated frame before
     728             :   // transform.
     729             :   bool mUntransformedVisibleRegion;
     730             :   bool mIsFixedToRootScrollFrame;
     731             : };
     732             : 
     733             : class PaintedLayerDataTree;
     734             : 
     735             : /**
     736             :  * This is tree node type for PaintedLayerDataTree.
     737             :  * Each node corresponds to a different animated geometry root, and contains
     738             :  * a stack of PaintedLayerDatas, in bottom-to-top order.
     739             :  * There is at most one node per animated geometry root. The ancestor and
     740             :  * descendant relations in PaintedLayerDataTree tree mirror those in the frame
     741             :  * tree.
     742             :  * Each node can have clip that describes the potential extents that items in
     743             :  * this node can cover. If mHasClip is false, it means that the node's contents
     744             :  * can move anywhere.
     745             :  * Testing against the clip instead of the node's actual contents has the
     746             :  * advantage that the node's contents can move or animate without affecting
     747             :  * content in other nodes. So we don't need to re-layerize during animations
     748             :  * (sync or async), and during async animations everything is guaranteed to
     749             :  * look correct.
     750             :  * The contents of a node's PaintedLayerData stack all share the node's
     751             :  * animated geometry root. The child nodes are on top of the PaintedLayerData
     752             :  * stack, in z-order, and the clip rects of the child nodes are allowed to
     753             :  * intersect with the visible region or visible above region of their parent
     754             :  * node's PaintedLayerDatas.
     755             :  */
     756             : class PaintedLayerDataNode {
     757             : public:
     758             :   PaintedLayerDataNode(PaintedLayerDataTree& aTree,
     759             :                        PaintedLayerDataNode* aParent,
     760             :                        AnimatedGeometryRoot* aAnimatedGeometryRoot);
     761             :   ~PaintedLayerDataNode();
     762             : 
     763        1598 :   AnimatedGeometryRoot* GetAnimatedGeometryRoot() const { return mAnimatedGeometryRoot; }
     764             : 
     765             :   /**
     766             :    * Whether this node's contents can potentially intersect aRect.
     767             :    * aRect is in our tree's ContainerState's coordinate space.
     768             :    */
     769           0 :   bool Intersects(const nsIntRect& aRect) const
     770           0 :     { return !mHasClip || mClipRect.Intersects(aRect); }
     771             : 
     772             :   /**
     773             :    * Create a PaintedLayerDataNode for aAnimatedGeometryRoot, add it to our
     774             :    * children, and return it.
     775             :    */
     776             :   PaintedLayerDataNode* AddChildNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot);
     777             : 
     778             :   /**
     779             :    * Find a PaintedLayerData in our mPaintedLayerDataStack that aItem can be
     780             :    * added to. Creates a new PaintedLayerData by calling
     781             :    * aNewPaintedLayerCallback if necessary.
     782             :    */
     783             :   template<typename NewPaintedLayerCallbackType>
     784             :   PaintedLayerData* FindPaintedLayerFor(const nsIntRect& aVisibleRect,
     785             :                                         bool aBackfaceHidden,
     786             :                                         const ActiveScrolledRoot* aASR,
     787             :                                         const DisplayItemClipChain* aClipChain,
     788             :                                         NewPaintedLayerCallbackType aNewPaintedLayerCallback);
     789             : 
     790             :   /**
     791             :    * Find an opaque background color for aRegion. Pulls a color from the parent
     792             :    * geometry root if appropriate, but only if that color is present underneath
     793             :    * the whole clip of this node, so that this node's contents can animate or
     794             :    * move (possibly async) without having to change the background color.
     795             :    * @param aUnderIndex Searching will start in mPaintedLayerDataStack right
     796             :    *                    below aUnderIndex.
     797             :    */
     798             :   enum { ABOVE_TOP = -1 };
     799             :   nscolor FindOpaqueBackgroundColor(const nsIntRegion& aRegion,
     800             :                                     int32_t aUnderIndex = ABOVE_TOP) const;
     801             :   /**
     802             :    * Same as FindOpaqueBackgroundColor, but only returns a color if absolutely
     803             :    * nothing is in between, so that it can be used for a layer that can move
     804             :    * anywhere inside our clip.
     805             :    */
     806             :   nscolor FindOpaqueBackgroundColorCoveringEverything() const;
     807             : 
     808             :   /**
     809             :    * Adds aRect to this node's top PaintedLayerData's mVisibleAboveRegion,
     810             :    * or mVisibleAboveBackgroundRegion if mPaintedLayerDataStack is empty.
     811             :    */
     812             :   void AddToVisibleAboveRegion(const nsIntRect& aRect);
     813             :   /**
     814             :    * Call this if all of our existing content can potentially be covered, so
     815             :    * nothing can merge with it and all new content needs to create new items
     816             :    * on top. This will finish all of our children and pop our whole
     817             :    * mPaintedLayerDataStack.
     818             :    */
     819             :   void SetAllDrawingAbove();
     820             : 
     821             :   /**
     822             :    * Finish this node: Finish all children, finish our PaintedLayer contents,
     823             :    * and (if requested) adjust our parent's visible above region to include
     824             :    * our clip.
     825             :    */
     826             :   void Finish(bool aParentNeedsAccurateVisibleAboveRegion);
     827             : 
     828             :   /**
     829             :    * Finish any children that intersect aRect.
     830             :    */
     831             :   void FinishChildrenIntersecting(const nsIntRect& aRect);
     832             : 
     833             :   /**
     834             :    * Finish all children.
     835             :    */
     836           0 :   void FinishAllChildren() { FinishAllChildren(true); }
     837             : 
     838             : protected:
     839             :   /**
     840             :    * Finish the topmost item in mPaintedLayerDataStack and pop it from the
     841             :    * stack.
     842             :    */
     843             :   void PopPaintedLayerData();
     844             :   /**
     845             :    * Finish all items in mPaintedLayerDataStack and clear the stack.
     846             :    */
     847             :   void PopAllPaintedLayerData();
     848             :   /**
     849             :    * Finish all of our child nodes, but don't touch mPaintedLayerDataStack.
     850             :    */
     851             :   void FinishAllChildren(bool aThisNodeNeedsAccurateVisibleAboveRegion);
     852             :   /**
     853             :    * Pass off opaque background color searching to our parent node, if we have
     854             :    * one.
     855             :    */
     856             :   nscolor FindOpaqueBackgroundColorInParentNode() const;
     857             : 
     858             :   PaintedLayerDataTree& mTree;
     859             :   PaintedLayerDataNode* mParent;
     860             :   AnimatedGeometryRoot* mAnimatedGeometryRoot;
     861             : 
     862             :   /**
     863             :    * Our contents: a PaintedLayerData stack and our child nodes.
     864             :    */
     865             :   nsTArray<PaintedLayerData> mPaintedLayerDataStack;
     866             : 
     867             :   /**
     868             :    * UniquePtr is used here in the sense of "unique ownership", i.e. there is
     869             :    * only one owner. Not in the sense of "this is the only pointer to the
     870             :    * node": There are two other, non-owning, pointers to our child nodes: The
     871             :    * node's respective children point to their parent node with their mParent
     872             :    * pointer, and the tree keeps a map of animated geometry root to node in its
     873             :    * mNodes member. These outside pointers are the reason that mChildren isn't
     874             :    * just an nsTArray<PaintedLayerDataNode> (since the pointers would become
     875             :    * invalid whenever the array expands its capacity).
     876             :    */
     877             :   nsTArray<UniquePtr<PaintedLayerDataNode>> mChildren;
     878             : 
     879             :   /**
     880             :    * The region that's covered between our "background" and the bottom of
     881             :    * mPaintedLayerDataStack. This is used to indicate whether we can pull
     882             :    * a background color from our parent node. If mVisibleAboveBackgroundRegion
     883             :    * should be considered infinite, mAllDrawingAboveBackground will be true and
     884             :    * the value of mVisibleAboveBackgroundRegion will be meaningless.
     885             :    */
     886             :   nsIntRegion mVisibleAboveBackgroundRegion;
     887             : 
     888             :   /**
     889             :    * Our clip, if we have any. If not, that means we can move anywhere, and
     890             :    * mHasClip will be false and mClipRect will be meaningless.
     891             :    */
     892             :   nsIntRect mClipRect;
     893             :   bool mHasClip;
     894             : 
     895             :   /**
     896             :    * Whether mVisibleAboveBackgroundRegion should be considered infinite.
     897             :    */
     898             :   bool mAllDrawingAboveBackground;
     899             : };
     900             : 
     901             : class ContainerState;
     902             : 
     903             : /**
     904             :  * A tree of PaintedLayerDataNodes. At any point in time, the tree only
     905             :  * contains nodes for animated geometry roots that new items can potentially
     906             :  * merge into. Any time content is added on top that overlaps existing things
     907             :  * in such a way that we no longer want to merge new items with some existing
     908             :  * content, that existing content gets "finished".
     909             :  * The public-facing methods of this class are FindPaintedLayerFor,
     910             :  * AddingOwnLayer, and Finish. The other public methods are for
     911             :  * PaintedLayerDataNode.
     912             :  * The tree calls out to its containing ContainerState for some things.
     913             :  * All coordinates / rects in the tree or the tree nodes are in the
     914             :  * ContainerState's coordinate space, i.e. relative to the reference frame and
     915             :  * in layer pixels.
     916             :  * The clip rects of sibling nodes never overlap. This is ensured by finishing
     917             :  * existing nodes before adding new ones, if this property were to be violated.
     918             :  * The root tree node doesn't get finished until the ContainerState is
     919             :  * finished.
     920             :  * The tree's root node is always the root reference frame of the builder. We
     921             :  * don't stop at the container state's mContainerAnimatedGeometryRoot because
     922             :  * some of our contents can have animated geometry roots that are not
     923             :  * descendants of the container's animated geometry root. Every animated
     924             :  * geometry root we encounter for our contents needs to have a defined place in
     925             :  * the tree.
     926             :  */
     927             : class PaintedLayerDataTree {
     928             : public:
     929         239 :   PaintedLayerDataTree(ContainerState& aContainerState,
     930             :                        nscolor& aBackgroundColor)
     931         239 :     : mContainerState(aContainerState)
     932         239 :     , mContainerUniformBackgroundColor(aBackgroundColor)
     933         239 :   {}
     934             : 
     935         239 :   ~PaintedLayerDataTree()
     936         239 :   {
     937         239 :     MOZ_ASSERT(!mRoot);
     938         239 :     MOZ_ASSERT(mNodes.Count() == 0);
     939         239 :   }
     940             : 
     941             :   /**
     942             :    * Notify our contents that some non-PaintedLayer content has been added.
     943             :    * *aRect needs to be a rectangle that doesn't move with respect to
     944             :    * aAnimatedGeometryRoot and that contains the added item.
     945             :    * If aRect is null, the extents will be considered infinite.
     946             :    * If aOutUniformBackgroundColor is non-null, it will be set to an opaque
     947             :    * color that can be pulled into the background of the added content, or
     948             :    * transparent if that is not possible.
     949             :    */
     950             :   void AddingOwnLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
     951             :                       const nsIntRect* aRect,
     952             :                       nscolor* aOutUniformBackgroundColor);
     953             : 
     954             :   /**
     955             :    * Find a PaintedLayerData for aItem. This can either be an existing
     956             :    * PaintedLayerData from inside a node in our tree, or a new one that gets
     957             :    * created by a call out to aNewPaintedLayerCallback.
     958             :    */
     959             :   template<typename NewPaintedLayerCallbackType>
     960             :   PaintedLayerData* FindPaintedLayerFor(AnimatedGeometryRoot* aAnimatedGeometryRoot,
     961             :                                         const ActiveScrolledRoot* aASR,
     962             :                                         const DisplayItemClipChain* aClipChain,
     963             :                                         const nsIntRect& aVisibleRect,
     964             :                                         bool aBackfaceidden,
     965             :                                         NewPaintedLayerCallbackType aNewPaintedLayerCallback);
     966             : 
     967             :   /**
     968             :    * Finish everything.
     969             :    */
     970             :   void Finish();
     971             : 
     972             :   /**
     973             :    * Get the parent animated geometry root of aAnimatedGeometryRoot.
     974             :    * That's either aAnimatedGeometryRoot's animated geometry root, or, if
     975             :    * that's aAnimatedGeometryRoot itself, then it's the animated geometry
     976             :    * root for aAnimatedGeometryRoot's cross-doc parent frame.
     977             :    */
     978             :   AnimatedGeometryRoot* GetParentAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot);
     979             : 
     980             :   /**
     981             :    * Whether aAnimatedGeometryRoot has an intrinsic clip that doesn't move with
     982             :    * respect to aAnimatedGeometryRoot's parent animated geometry root.
     983             :    * If aAnimatedGeometryRoot is a scroll frame, this will be the scroll frame's
     984             :    * scroll port, otherwise there is no clip.
     985             :    * This method doesn't have much to do with PaintedLayerDataTree, but this is
     986             :    * where we have easy access to a display list builder, which we use to get
     987             :    * the clip rect result into the right coordinate space.
     988             :    */
     989             :   bool IsClippedWithRespectToParentAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
     990             :                                                         nsIntRect* aOutClip);
     991             : 
     992             :   /**
     993             :    * Called by PaintedLayerDataNode when it is finished, so that we can drop
     994             :    * our pointers to it.
     995             :    */
     996             :   void NodeWasFinished(AnimatedGeometryRoot* aAnimatedGeometryRoot);
     997             : 
     998             :   nsDisplayListBuilder* Builder() const;
     999        1819 :   ContainerState& ContState() const { return mContainerState; }
    1000         142 :   nscolor UniformBackgroundColor() const { return mContainerUniformBackgroundColor; }
    1001             : 
    1002             : protected:
    1003             :   /**
    1004             :    * Finish all nodes that potentially intersect *aRect, where *aRect is a rect
    1005             :    * that doesn't move with respect to aAnimatedGeometryRoot.
    1006             :    * If aRect is null, *aRect will be considered infinite.
    1007             :    */
    1008             :   void FinishPotentiallyIntersectingNodes(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    1009             :                                           const nsIntRect* aRect);
    1010             : 
    1011             :   /**
    1012             :    * Make sure that there is a node for aAnimatedGeometryRoot and all of its
    1013             :    * ancestor geometry roots. Return the node for aAnimatedGeometryRoot.
    1014             :    */
    1015             :   PaintedLayerDataNode* EnsureNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot);
    1016             : 
    1017             :   /**
    1018             :    * Find an existing node in the tree for an ancestor of aAnimatedGeometryRoot.
    1019             :    * *aOutAncestorChild will be set to the last ancestor that was encountered
    1020             :    * in the search up from aAnimatedGeometryRoot; it will be a child animated
    1021             :    * geometry root of the result, if neither are null.
    1022             :    */
    1023             :   PaintedLayerDataNode*
    1024             :     FindNodeForAncestorAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    1025             :                                             AnimatedGeometryRoot** aOutAncestorChild);
    1026             : 
    1027             :   ContainerState& mContainerState;
    1028             :   UniquePtr<PaintedLayerDataNode> mRoot;
    1029             : 
    1030             :   /**
    1031             :    * The uniform opaque color from behind this container layer, or
    1032             :    * NS_RGBA(0,0,0,0) if the background behind this container layer is not
    1033             :    * uniform and opaque. This color can be pulled into PaintedLayers that are
    1034             :    * directly above the background.
    1035             :    */
    1036             :   nscolor mContainerUniformBackgroundColor;
    1037             : 
    1038             :   /**
    1039             :    * A hash map for quick access the node belonging to a particular animated
    1040             :    * geometry root.
    1041             :    */
    1042             :   nsDataHashtable<nsPtrHashKey<AnimatedGeometryRoot>, PaintedLayerDataNode*> mNodes;
    1043             : };
    1044             : 
    1045             : /**
    1046             :  * This is a helper object used to build up the layer children for
    1047             :  * a ContainerLayer.
    1048             :  */
    1049         239 : class ContainerState {
    1050             : public:
    1051         239 :   ContainerState(nsDisplayListBuilder* aBuilder,
    1052             :                  LayerManager* aManager,
    1053             :                  FrameLayerBuilder* aLayerBuilder,
    1054             :                  nsIFrame* aContainerFrame,
    1055             :                  nsDisplayItem* aContainerItem,
    1056             :                  const nsRect& aContainerBounds,
    1057             :                  ContainerLayer* aContainerLayer,
    1058             :                  const ContainerLayerParameters& aParameters,
    1059             :                  bool aFlattenToSingleLayer,
    1060             :                  nscolor aBackgroundColor,
    1061             :                  const ActiveScrolledRoot* aContainerASR,
    1062             :                  const ActiveScrolledRoot* aContainerScrollMetadataASR,
    1063         239 :                  const ActiveScrolledRoot* aContainerCompositorASR) :
    1064             :     mBuilder(aBuilder), mManager(aManager),
    1065             :     mLayerBuilder(aLayerBuilder),
    1066             :     mContainerFrame(aContainerFrame),
    1067             :     mContainerLayer(aContainerLayer),
    1068             :     mContainerBounds(aContainerBounds),
    1069             :     mContainerASR(aContainerASR),
    1070             :     mContainerScrollMetadataASR(aContainerScrollMetadataASR),
    1071             :     mContainerCompositorASR(aContainerCompositorASR),
    1072             :     mParameters(aParameters),
    1073             :     mPaintedLayerDataTree(*this, aBackgroundColor),
    1074             :     mFlattenToSingleLayer(aFlattenToSingleLayer),
    1075         239 :     mLastDisplayPortAGR(nullptr)
    1076             :   {
    1077         239 :     nsPresContext* presContext = aContainerFrame->PresContext();
    1078         239 :     mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
    1079         239 :     mContainerReferenceFrame =
    1080         195 :       const_cast<nsIFrame*>(aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
    1081         434 :                                              mBuilder->FindReferenceFrameFor(mContainerFrame));
    1082         239 :     bool isAtRoot = !aContainerItem || (aContainerItem->Frame() == mBuilder->RootReferenceFrame());
    1083         239 :     MOZ_ASSERT(!isAtRoot || mContainerReferenceFrame == mBuilder->RootReferenceFrame());
    1084         239 :     mContainerAnimatedGeometryRoot = isAtRoot
    1085         239 :       ? aBuilder->GetRootAnimatedGeometryRoot()
    1086             :       : aContainerItem->GetAnimatedGeometryRoot();
    1087         239 :     MOZ_ASSERT(!mBuilder->IsPaintingToWindow() ||
    1088             :       nsLayoutUtils::IsAncestorFrameCrossDoc(mBuilder->RootReferenceFrame(),
    1089             :                                              *mContainerAnimatedGeometryRoot));
    1090             :     // When AllowResidualTranslation is false, display items will be drawn
    1091             :     // scaled with a translation by integer pixels, so we know how the snapping
    1092             :     // will work.
    1093         478 :     mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
    1094         239 :       !mParameters.AllowResidualTranslation();
    1095         239 :     CollectOldLayers();
    1096         239 :   }
    1097             : 
    1098             :   /**
    1099             :    * This is the method that actually walks a display list and builds
    1100             :    * the child layers.
    1101             :    */
    1102             :   void ProcessDisplayItems(nsDisplayList* aList);
    1103             :   /**
    1104             :    * This finalizes all the open PaintedLayers by popping every element off
    1105             :    * mPaintedLayerDataStack, then sets the children of the container layer
    1106             :    * to be all the layers in mNewChildLayers in that order and removes any
    1107             :    * layers as children of the container that aren't in mNewChildLayers.
    1108             :    * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
    1109             :    * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
    1110             :    */
    1111             :   void Finish(uint32_t *aTextContentFlags,
    1112             :               const nsIntRect& aContainerPixelBounds,
    1113             :               nsDisplayList* aChildItems, bool* aHasComponentAlphaChildren);
    1114             : 
    1115         239 :   nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
    1116             : 
    1117        2610 :   nsIntRect ScaleToNearestPixels(const nsRect& aRect) const
    1118             :   {
    1119        2610 :     return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
    1120        5220 :                                       mAppUnitsPerDevPixel);
    1121             :   }
    1122         159 :   nsIntRegion ScaleRegionToNearestPixels(const nsRegion& aRegion) const
    1123             :   {
    1124         159 :     return aRegion.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
    1125         318 :                                         mAppUnitsPerDevPixel);
    1126             :   }
    1127        4848 :   nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap = false) const
    1128             :   {
    1129        4848 :     if (aSnap && mSnappingEnabled) {
    1130         961 :       return ScaleToNearestPixels(aRect);
    1131             :     }
    1132        3887 :     return aRect.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
    1133        7774 :                                       mAppUnitsPerDevPixel);
    1134             :   }
    1135           0 :   nsIntRegion ScaleToOutsidePixels(const nsRegion& aRegion, bool aSnap = false) const
    1136             :   {
    1137           0 :     if (aSnap && mSnappingEnabled) {
    1138           0 :       return ScaleRegionToNearestPixels(aRegion);
    1139             :     }
    1140           0 :     return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
    1141           0 :                                         mAppUnitsPerDevPixel);
    1142             :   }
    1143          65 :   nsIntRect ScaleToInsidePixels(const nsRect& aRect, bool aSnap = false) const
    1144             :   {
    1145          65 :     if (aSnap && mSnappingEnabled) {
    1146          63 :       return ScaleToNearestPixels(aRect);
    1147             :     }
    1148           2 :     return aRect.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
    1149           4 :                                      mAppUnitsPerDevPixel);
    1150             :   }
    1151             : 
    1152         185 :   nsIntRegion ScaleRegionToInsidePixels(const nsRegion& aRegion, bool aSnap = false) const
    1153             :   {
    1154         185 :     if (aSnap && mSnappingEnabled) {
    1155         159 :       return ScaleRegionToNearestPixels(aRegion);
    1156             :     }
    1157          26 :     return aRegion.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
    1158          52 :                                         mAppUnitsPerDevPixel);
    1159             :   }
    1160             : 
    1161         690 :   nsIntRegion ScaleRegionToOutsidePixels(const nsRegion& aRegion, bool aSnap = false) const
    1162             :   {
    1163         690 :     if (aSnap && mSnappingEnabled) {
    1164           0 :       return ScaleRegionToNearestPixels(aRegion);
    1165             :     }
    1166         690 :     return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
    1167        1380 :                                         mAppUnitsPerDevPixel);
    1168             :   }
    1169             : 
    1170        1298 :   nsIFrame* GetContainerFrame() const { return mContainerFrame; }
    1171         484 :   nsDisplayListBuilder* Builder() const { return mBuilder; }
    1172             : 
    1173             :   /**
    1174             :    * Check if we are currently inside an inactive layer.
    1175             :    */
    1176        1779 :   bool IsInInactiveLayer() const {
    1177        1779 :     return mLayerBuilder->GetContainingPaintedLayerData();
    1178             :   }
    1179             : 
    1180             :   /**
    1181             :    * Sets aOuterVisibleRegion as aLayer's visible region.
    1182             :    * @param aOuterVisibleRegion
    1183             :    *   is in the coordinate space of the container reference frame.
    1184             :    * @param aLayerContentsVisibleRect, if non-null, is in the layer's own
    1185             :    *   coordinate system.
    1186             :    * @param aOuterUntransformed is true if the given aOuterVisibleRegion
    1187             :    *   is already untransformed with the matrix of the layer.
    1188             :    */
    1189             :   void SetOuterVisibleRegionForLayer(Layer* aLayer,
    1190             :                                      const nsIntRegion& aOuterVisibleRegion,
    1191             :                                      const nsIntRect* aLayerContentsVisibleRect = nullptr,
    1192             :                                      bool aOuterUntransformed = false) const;
    1193             : 
    1194             :   /**
    1195             :    * Try to determine whether the PaintedLayer aData has a single opaque color
    1196             :    * covering aRect. If successful, return that color, otherwise return
    1197             :    * NS_RGBA(0,0,0,0).
    1198             :    * If aRect turns out not to intersect any content in the layer,
    1199             :    * *aOutIntersectsLayer will be set to false.
    1200             :    */
    1201             :   nscolor FindOpaqueBackgroundColorInLayer(const PaintedLayerData* aData,
    1202             :                                            const nsIntRect& aRect,
    1203             :                                            bool* aOutIntersectsLayer) const;
    1204             : 
    1205             :   /**
    1206             :    * Indicate that we are done adding items to the PaintedLayer represented by
    1207             :    * aData. Make sure that a real PaintedLayer exists for it, and set the final
    1208             :    * visible region and opaque-content.
    1209             :    */
    1210             :   template<typename FindOpaqueBackgroundColorCallbackType>
    1211             :   void FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor);
    1212             : 
    1213             : protected:
    1214             :   friend class PaintedLayerData;
    1215             : 
    1216             :   LayerManager::PaintedLayerCreationHint
    1217             :     GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot);
    1218             : 
    1219             :   /**
    1220             :    * Creates a new PaintedLayer and sets up the transform on the PaintedLayer
    1221             :    * to account for scrolling.
    1222             :    */
    1223             :   already_AddRefed<PaintedLayer> CreatePaintedLayer(PaintedLayerData* aData);
    1224             : 
    1225             :   /**
    1226             :    * Find a PaintedLayer for recycling, recycle it and prepare it for use, or
    1227             :    * return null if no suitable layer was found.
    1228             :    */
    1229             :   already_AddRefed<PaintedLayer> AttemptToRecyclePaintedLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    1230             :                                                               nsDisplayItem* aItem,
    1231             :                                                               const nsPoint& aTopLeft);
    1232             :   /**
    1233             :    * Recycle aLayer and do any necessary invalidation.
    1234             :    */
    1235             :   PaintedDisplayItemLayerUserData* RecyclePaintedLayer(PaintedLayer* aLayer,
    1236             :                                                        AnimatedGeometryRoot* aAnimatedGeometryRoot,
    1237             :                                                        bool& didResetScrollPositionForLayerPixelAlignment);
    1238             : 
    1239             :   /**
    1240             :    * Perform the last step of CreatePaintedLayer / AttemptToRecyclePaintedLayer:
    1241             :    * Initialize aData, set up the layer's transform for scrolling, and
    1242             :    * invalidate the layer for layer pixel alignment changes if necessary.
    1243             :    */
    1244             :   void PreparePaintedLayerForUse(PaintedLayer* aLayer,
    1245             :                                  PaintedDisplayItemLayerUserData* aData,
    1246             :                                  AnimatedGeometryRoot* aAnimatedGeometryRoot,
    1247             :                                  const nsIFrame* aReferenceFrame,
    1248             :                                  const nsPoint& aTopLeft,
    1249             :                                  bool aDidResetScrollPositionForLayerPixelAlignment);
    1250             : 
    1251             :   /**
    1252             :    * Attempt to prepare an ImageLayer based upon the provided PaintedLayerData.
    1253             :    * Returns nullptr on failure.
    1254             :    */
    1255             :   already_AddRefed<Layer> PrepareImageLayer(PaintedLayerData* aData);
    1256             : 
    1257             :   /**
    1258             :    * Attempt to prepare a ColorLayer based upon the provided PaintedLayerData.
    1259             :    * Returns nullptr on failure.
    1260             :    */
    1261             :   already_AddRefed<Layer> PrepareColorLayer(PaintedLayerData* aData);
    1262             : 
    1263             :   /**
    1264             :    * Grab the next recyclable ColorLayer, or create one if there are no
    1265             :    * more recyclable ColorLayers.
    1266             :    */
    1267             :   already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(PaintedLayer* aPainted);
    1268             :   /**
    1269             :    * Grab the next recyclable ImageLayer, or create one if there are no
    1270             :    * more recyclable ImageLayers.
    1271             :    */
    1272             :   already_AddRefed<ImageLayer> CreateOrRecycleImageLayer(PaintedLayer* aPainted);
    1273             :   /**
    1274             :    * Grab a recyclable ImageLayer for use as a mask layer for aLayer (that is a
    1275             :    * mask layer which has been used for aLayer before), or create one if such
    1276             :    * a layer doesn't exist.
    1277             :    *
    1278             :    * Since mask layers can exist either on the layer directly, or as a side-
    1279             :    * attachment to FrameMetrics (for ancestor scrollframe clips), we key the
    1280             :    * recycle operation on both the originating layer and the mask layer's
    1281             :    * index in the layer, if any.
    1282             :    */
    1283             :   struct MaskLayerKey;
    1284             :   already_AddRefed<ImageLayer>
    1285             :   CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey,
    1286             :                                    const std::function<void(Layer* aLayer)>& aSetUserData);
    1287             :   /**
    1288             :    * Grabs all PaintedLayers and ColorLayers from the ContainerLayer and makes them
    1289             :    * available for recycling.
    1290             :    */
    1291             :   void CollectOldLayers();
    1292             :   /**
    1293             :    * If aItem used to belong to a PaintedLayer, invalidates the area of
    1294             :    * aItem in that layer. If aNewLayer is a PaintedLayer, invalidates the area of
    1295             :    * aItem in that layer.
    1296             :    */
    1297             :   void InvalidateForLayerChange(nsDisplayItem* aItem,
    1298             :                                 PaintedLayer* aNewLayer);
    1299             :   /**
    1300             :    * Returns true if aItem's opaque area (in aOpaque) covers the entire
    1301             :    * scrollable area of its presshell.
    1302             :    */
    1303             :   bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque);
    1304             : 
    1305             :   /**
    1306             :    * Set ScrollMetadata and scroll-induced clipping on aEntry's layer.
    1307             :    */
    1308             :   void SetupScrollingMetadata(NewLayerEntry* aEntry);
    1309             : 
    1310             :   /**
    1311             :    * Applies occlusion culling.
    1312             :    * For each layer in mNewChildLayers, remove from its visible region the
    1313             :    * opaque regions of the layers at higher z-index, but only if they have
    1314             :    * the same animated geometry root and fixed-pos frame ancestor.
    1315             :    * The opaque region for the child layers that share the same animated
    1316             :    * geometry root as the container frame is returned in
    1317             :    * *aOpaqueRegionForContainer.
    1318             :    *
    1319             :    * Also sets scroll metadata on the layers.
    1320             :    */
    1321             :   void PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer);
    1322             : 
    1323             :   /**
    1324             :    * Computes the snapped opaque area of aItem. Sets aList's opaque flag
    1325             :    * if it covers the entire list bounds. Sets *aHideAllLayersBelow to true
    1326             :    * this item covers the entire viewport so that all layers below are
    1327             :    * permanently invisible.
    1328             :    */
    1329             :   nsIntRegion ComputeOpaqueRect(nsDisplayItem* aItem,
    1330             :                                 AnimatedGeometryRoot* aAnimatedGeometryRoot,
    1331             :                                 const ActiveScrolledRoot* aASR,
    1332             :                                 const DisplayItemClip& aClip,
    1333             :                                 nsDisplayList* aList,
    1334             :                                 bool* aHideAllLayersBelow,
    1335             :                                 bool* aOpaqueForAnimatedGeometryRootParent);
    1336             : 
    1337             :   /**
    1338             :    * Return a PaintedLayerData object that is initialized for a layer that
    1339             :    * aItem will be assigned to.
    1340             :    * @param  aItem                 The item that is going to be added.
    1341             :    * @param  aVisibleRect          The visible rect of the item.
    1342             :    * @param  aAnimatedGeometryRoot The item's animated geometry root.
    1343             :    * @param  aASR                  The active scrolled root that moves this PaintedLayer.
    1344             :    * @param  aClipChain            The clip chain that the compositor needs to
    1345             :    *                               apply to this layer.
    1346             :    * @param  aScrollMetadataASR    The leaf ASR for which scroll metadata needs to be
    1347             :    *                               set on the layer, because either the layer itself
    1348             :    *                               or its scrolled clip need to move with that ASR.
    1349             :    * @param  aTopLeft              The offset between aAnimatedGeometryRoot and
    1350             :    *                               the reference frame.
    1351             :    */
    1352             :   PaintedLayerData NewPaintedLayerData(nsDisplayItem* aItem,
    1353             :                                        AnimatedGeometryRoot* aAnimatedGeometryRoot,
    1354             :                                        const ActiveScrolledRoot* aASR,
    1355             :                                        const DisplayItemClipChain* aClipChain,
    1356             :                                        const ActiveScrolledRoot* aScrollMetadataASR,
    1357             :                                        const nsPoint& aTopLeft);
    1358             : 
    1359             :   /* Build a mask layer to represent the clipping region. Will return null if
    1360             :    * there is no clipping specified or a mask layer cannot be built.
    1361             :    * Builds an ImageLayer for the appropriate backend; the mask is relative to
    1362             :    * aLayer's visible region.
    1363             :    * aLayer is the layer to be clipped.
    1364             :    * relative to the container reference frame
    1365             :    * aRoundedRectClipCount is used when building mask layers for PaintedLayers,
    1366             :    * SetupMaskLayer will build a mask layer for only the first
    1367             :    * aRoundedRectClipCount rounded rects in aClip
    1368             :    */
    1369             :   void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
    1370             :                       uint32_t aRoundedRectClipCount = UINT32_MAX);
    1371             : 
    1372             :   /**
    1373             :    * If |aClip| has rounded corners, create a mask layer for them, and
    1374             :    * add it to |aLayer|'s ancestor mask layers, returning an index into
    1375             :    * the array of ancestor mask layers. Returns an empty Maybe if
    1376             :    * |aClip| does not have rounded corners, or if no mask layer could
    1377             :    * be created.
    1378             :    */
    1379             :   Maybe<size_t> SetupMaskLayerForScrolledClip(Layer* aLayer,
    1380             :                                               const DisplayItemClip& aClip);
    1381             : 
    1382             :   /*
    1383             :    * Create/find a mask layer with suitable size for aMaskItem to paint
    1384             :    * css-positioned-masking onto.
    1385             :    */
    1386             :   void SetupMaskLayerForCSSMask(Layer* aLayer, nsDisplayMask* aMaskItem);
    1387             : 
    1388             :   already_AddRefed<Layer> CreateMaskLayer(
    1389             :     Layer *aLayer, const DisplayItemClip& aClip,
    1390             :     const Maybe<size_t>& aForAncestorMaskLayer,
    1391             :     uint32_t aRoundedRectClipCount = UINT32_MAX);
    1392             : 
    1393             :   bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
    1394             :                                   AnimatedGeometryRoot** aAnimatedGeometryRoot,
    1395             :                                   const ActiveScrolledRoot** aASR);
    1396             : 
    1397             :   /**
    1398             :    * Get the display port for an AGR.
    1399             :    * The result would be cached for later reusing.
    1400             :    */
    1401             :   nsRect GetDisplayPortForAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot);
    1402             : 
    1403             :   nsDisplayListBuilder*            mBuilder;
    1404             :   LayerManager*                    mManager;
    1405             :   FrameLayerBuilder*               mLayerBuilder;
    1406             :   nsIFrame*                        mContainerFrame;
    1407             :   nsIFrame*                        mContainerReferenceFrame;
    1408             :   AnimatedGeometryRoot*            mContainerAnimatedGeometryRoot;
    1409             :   ContainerLayer*                  mContainerLayer;
    1410             :   nsRect                           mContainerBounds;
    1411             : 
    1412             :   // Due to the way we store scroll annotations in the layer tree, we need to
    1413             :   // keep track of three (possibly different) ASRs here.
    1414             :   // mContainerASR is the ASR of the container display item that this
    1415             :   // ContainerState was created for.
    1416             :   // mContainerScrollMetadataASR is the ASR of the leafmost scroll metadata
    1417             :   // that's in effect on mContainerLayer.
    1418             :   // mContainerCompositorASR is the ASR that mContainerLayer moves with on
    1419             :   // the compositor / APZ side, taking into account both the scroll meta data
    1420             :   // and the fixed position annotation on itself and its ancestors.
    1421             :   const ActiveScrolledRoot*        mContainerASR;
    1422             :   const ActiveScrolledRoot*        mContainerScrollMetadataASR;
    1423             :   const ActiveScrolledRoot*        mContainerCompositorASR;
    1424             : #ifdef DEBUG
    1425             :   nsRect                           mAccumulatedChildBounds;
    1426             : #endif
    1427             :   ContainerLayerParameters         mParameters;
    1428             :   /**
    1429             :    * The region of PaintedLayers that should be invalidated every time
    1430             :    * we recycle one.
    1431             :    */
    1432             :   nsIntRegion                      mInvalidPaintedContent;
    1433             :   PaintedLayerDataTree             mPaintedLayerDataTree;
    1434             :   /**
    1435             :    * We collect the list of children in here. During ProcessDisplayItems,
    1436             :    * the layers in this array either have mContainerLayer as their parent,
    1437             :    * or no parent.
    1438             :    * PaintedLayers have two entries in this array: the second one is used only if
    1439             :    * the PaintedLayer is optimized away to a ColorLayer or ImageLayer.
    1440             :    * It's essential that this array is only appended to, since PaintedLayerData
    1441             :    * records the index of its PaintedLayer in this array.
    1442             :    */
    1443             :   typedef AutoTArray<NewLayerEntry,1> AutoLayersArray;
    1444             :   AutoLayersArray                  mNewChildLayers;
    1445             :   nsTHashtable<nsRefPtrHashKey<PaintedLayer>> mPaintedLayersAvailableForRecycling;
    1446             :   nscoord                          mAppUnitsPerDevPixel;
    1447             :   bool                             mSnappingEnabled;
    1448             :   bool                             mFlattenToSingleLayer;
    1449             : 
    1450           0 :   struct MaskLayerKey {
    1451             :     MaskLayerKey() : mLayer(nullptr) {}
    1452           0 :     MaskLayerKey(Layer* aLayer, const Maybe<size_t>& aAncestorIndex)
    1453           0 :       : mLayer(aLayer),
    1454           0 :         mAncestorIndex(aAncestorIndex)
    1455           0 :     {}
    1456             : 
    1457           0 :     PLDHashNumber Hash() const {
    1458             :       // Hash the layer and add the layer index to the hash.
    1459           0 :       return (NS_PTR_TO_UINT32(mLayer) >> 2)
    1460           0 :              + (mAncestorIndex ? (*mAncestorIndex + 1) : 0);
    1461             :     }
    1462           0 :     bool operator ==(const MaskLayerKey& aOther) const {
    1463           0 :       return mLayer == aOther.mLayer &&
    1464           0 :              mAncestorIndex == aOther.mAncestorIndex;
    1465             :     }
    1466             : 
    1467             :     Layer* mLayer;
    1468             :     Maybe<size_t> mAncestorIndex;
    1469             :   };
    1470             : 
    1471             :   nsDataHashtable<nsGenericHashKey<MaskLayerKey>, RefPtr<ImageLayer>>
    1472             :     mRecycledMaskImageLayers;
    1473             :   // Keep display port of AGR to avoid wasting time on doing the same
    1474             :   // thing repeatly.
    1475             :   AnimatedGeometryRoot* mLastDisplayPortAGR;
    1476             :   nsRect mLastDisplayPortRect;
    1477             : };
    1478             : 
    1479         408 : class PaintedDisplayItemLayerUserData : public LayerUserData
    1480             : {
    1481             : public:
    1482         145 :   PaintedDisplayItemLayerUserData() :
    1483             :     mMaskClipCount(0),
    1484             :     mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
    1485             :     mFontSmoothingBackgroundColor(NS_RGBA(0,0,0,0)),
    1486             :     mXScale(1.f), mYScale(1.f),
    1487             :     mAppUnitsPerDevPixel(0),
    1488             :     mTranslation(0, 0),
    1489         145 :     mAnimatedGeometryRootPosition(0, 0) {}
    1490             : 
    1491             :   /**
    1492             :    * Record the number of clips in the PaintedLayer's mask layer.
    1493             :    * Should not be reset when the layer is recycled since it is used to track
    1494             :    * changes in the use of mask layers.
    1495             :    */
    1496             :   uint32_t mMaskClipCount;
    1497             : 
    1498             :   /**
    1499             :    * A color that should be painted over the bounds of the layer's visible
    1500             :    * region before any other content is painted.
    1501             :    */
    1502             :   nscolor mForcedBackgroundColor;
    1503             : 
    1504             :   /**
    1505             :    * The target background color for smoothing fonts that are drawn on top of
    1506             :    * transparent parts of the layer.
    1507             :    */
    1508             :   nscolor mFontSmoothingBackgroundColor;
    1509             : 
    1510             :   /**
    1511             :    * The resolution scale used.
    1512             :    */
    1513             :   float mXScale, mYScale;
    1514             : 
    1515             :   /**
    1516             :    * The appunits per dev pixel for the items in this layer.
    1517             :    */
    1518             :   nscoord mAppUnitsPerDevPixel;
    1519             : 
    1520             :   /**
    1521             :    * The offset from the PaintedLayer's 0,0 to the
    1522             :    * reference frame. This isn't necessarily the same as the transform
    1523             :    * set on the PaintedLayer since we might also be applying an extra
    1524             :    * offset specified by the parent ContainerLayer/
    1525             :    */
    1526             :   nsIntPoint mTranslation;
    1527             : 
    1528             :   /**
    1529             :    * We try to make 0,0 of the PaintedLayer be the top-left of the
    1530             :    * border-box of the "active scrolled root" frame (i.e. the nearest ancestor
    1531             :    * frame for the display items that is being actively scrolled). But
    1532             :    * we force the PaintedLayer transform to be an integer translation, and we may
    1533             :    * have a resolution scale, so we have to snap the PaintedLayer transform, so
    1534             :    * 0,0 may not be exactly the top-left of the active scrolled root. Here we
    1535             :    * store the coordinates in PaintedLayer space of the top-left of the
    1536             :    * active scrolled root.
    1537             :    */
    1538             :   gfxPoint mAnimatedGeometryRootPosition;
    1539             : 
    1540             :   nsIntRegion mRegionToInvalidate;
    1541             : 
    1542             :   // The offset between the active scrolled root of this layer
    1543             :   // and the root of the container for the previous and current
    1544             :   // paints respectively.
    1545             :   nsPoint mLastAnimatedGeometryRootOrigin;
    1546             :   nsPoint mAnimatedGeometryRootOrigin;
    1547             : 
    1548             :   RefPtr<ColorLayer> mColorLayer;
    1549             :   RefPtr<ImageLayer> mImageLayer;
    1550             : 
    1551             :   // The region for which display item visibility for this layer has already
    1552             :   // been calculated. Used to reduce the number of calls to
    1553             :   // RecomputeVisibilityForItems if it is known in advance that a larger
    1554             :   // region will be painted during a transaction than in a single call to
    1555             :   // DrawPaintedLayer, for example when progressive paint is enabled.
    1556             :   nsIntRegion mVisibilityComputedRegion;
    1557             : 
    1558             :   /**
    1559             :    * This is set when the painted layer has no component alpha.
    1560             :    */
    1561             :   bool mDisabledAlpha;
    1562             : };
    1563             : 
    1564             : /*
    1565             :  * User data for layers which will be used as masks.
    1566             :  */
    1567           0 : struct MaskLayerUserData : public LayerUserData
    1568             : {
    1569           0 :   MaskLayerUserData()
    1570           0 :     : mScaleX(-1.0f)
    1571             :     , mScaleY(-1.0f)
    1572           0 :     , mAppUnitsPerDevPixel(-1)
    1573           0 :   { }
    1574           0 :   MaskLayerUserData(const DisplayItemClip& aClip,
    1575             :                     uint32_t aRoundedRectClipCount,
    1576             :                     int32_t aAppUnitsPerDevPixel,
    1577             :                     const ContainerLayerParameters& aParams)
    1578           0 :     : mScaleX(aParams.mXScale)
    1579           0 :     , mScaleY(aParams.mYScale)
    1580             :     , mOffset(aParams.mOffset)
    1581           0 :     , mAppUnitsPerDevPixel(aAppUnitsPerDevPixel)
    1582             :   {
    1583           0 :     aClip.AppendRoundedRects(&mRoundedClipRects, aRoundedRectClipCount);
    1584           0 :   }
    1585             : 
    1586           0 :   void operator=(MaskLayerUserData&& aOther)
    1587             :   {
    1588           0 :     mScaleX = aOther.mScaleX;
    1589           0 :     mScaleY = aOther.mScaleY;
    1590           0 :     mOffset = aOther.mOffset;
    1591           0 :     mAppUnitsPerDevPixel = aOther.mAppUnitsPerDevPixel;
    1592           0 :     mRoundedClipRects.SwapElements(aOther.mRoundedClipRects);
    1593           0 :   }
    1594             : 
    1595             :   bool
    1596           0 :   operator== (const MaskLayerUserData& aOther) const
    1597             :   {
    1598           0 :     return mRoundedClipRects == aOther.mRoundedClipRects &&
    1599           0 :            mScaleX == aOther.mScaleX &&
    1600           0 :            mScaleY == aOther.mScaleY &&
    1601           0 :            mOffset == aOther.mOffset &&
    1602           0 :            mAppUnitsPerDevPixel == aOther.mAppUnitsPerDevPixel;
    1603             :   }
    1604             : 
    1605             :   // Keeps a MaskLayerImageKey alive by managing its mLayerCount member-var
    1606             :   MaskLayerImageCache::MaskLayerImageKeyRef mImageKey;
    1607             :   // properties of the mask layer; the mask layer may be re-used if these
    1608             :   // remain unchanged.
    1609             :   nsTArray<DisplayItemClip::RoundedRect> mRoundedClipRects;
    1610             :   // scale from the masked layer which is applied to the mask
    1611             :   float mScaleX, mScaleY;
    1612             :   // The ContainerLayerParameters offset which is applied to the mask's transform.
    1613             :   nsIntPoint mOffset;
    1614             :   int32_t mAppUnitsPerDevPixel;
    1615             : };
    1616             : 
    1617             : /*
    1618             :  * User data for layers which will be used as masks for css positioned mask.
    1619             :  */
    1620           0 : struct CSSMaskLayerUserData : public LayerUserData
    1621             : {
    1622           0 :   CSSMaskLayerUserData()
    1623           0 :     : mMaskStyle(nsStyleImageLayers::LayerType::Mask)
    1624           0 :   { }
    1625             : 
    1626           0 :   CSSMaskLayerUserData(nsIFrame* aFrame, const nsIntRect& aMaskBounds,
    1627             :                        const nsPoint& aMaskLayerOffset)
    1628           0 :     : mMaskBounds(aMaskBounds),
    1629           0 :       mMaskStyle(aFrame->StyleSVGReset()->mMask),
    1630           0 :       mMaskLayerOffset(aMaskLayerOffset)
    1631             :   {
    1632           0 :   }
    1633             : 
    1634           0 :   void operator=(CSSMaskLayerUserData&& aOther)
    1635             :   {
    1636           0 :     mMaskBounds = aOther.mMaskBounds;
    1637           0 :     mMaskStyle = Move(aOther.mMaskStyle);
    1638           0 :     mMaskLayerOffset = aOther.mMaskLayerOffset;
    1639           0 :   }
    1640             : 
    1641             :   bool
    1642           0 :   operator==(const CSSMaskLayerUserData& aOther) const
    1643             :   {
    1644           0 :     if (!mMaskBounds.IsEqualInterior(aOther.mMaskBounds)) {
    1645           0 :       return false;
    1646             :     }
    1647             : 
    1648             :     // Make sure we draw the same portion of the mask onto mask layer.
    1649           0 :     if (mMaskLayerOffset != aOther.mMaskLayerOffset) {
    1650           0 :       return false;
    1651             :     }
    1652             : 
    1653           0 :     return mMaskStyle == aOther.mMaskStyle;
    1654             :   }
    1655             : 
    1656             : private:
    1657             :   nsIntRect mMaskBounds;
    1658             :   nsStyleImageLayers mMaskStyle;
    1659             :   nsPoint mMaskLayerOffset; // The offset from the origin of mask bounds to
    1660             :                             // the origin of mask layer.
    1661             : };
    1662             : 
    1663             : /*
    1664             :  * A helper object to create a draw target for painting mask and create a
    1665             :  * image container to hold the drawing result. The caller can then bind this
    1666             :  * image container with a image mask layer via ImageLayer::SetContainer.
    1667             :  */
    1668             : class MaskImageData
    1669             : {
    1670             : public:
    1671           0 :   MaskImageData(const gfx::IntSize& aSize, LayerManager* aLayerManager)
    1672           0 :     : mTextureClientLocked(false)
    1673             :     , mSize(aSize)
    1674           0 :     , mLayerManager(aLayerManager)
    1675             :   {
    1676           0 :     MOZ_ASSERT(!mSize.IsEmpty());
    1677           0 :     MOZ_ASSERT(mLayerManager);
    1678           0 :   }
    1679             : 
    1680           0 :   ~MaskImageData()
    1681           0 :   {
    1682           0 :     if (mTextureClientLocked) {
    1683           0 :       MOZ_ASSERT(mTextureClient);
    1684             :       // Clear DrawTarget before Unlock.
    1685           0 :       mDrawTarget = nullptr;
    1686           0 :       mTextureClient->Unlock();
    1687             :     }
    1688           0 :   }
    1689             : 
    1690           0 :   gfx::DrawTarget* CreateDrawTarget()
    1691             :   {
    1692           0 :     if (mDrawTarget) {
    1693           0 :       return mDrawTarget;
    1694             :     }
    1695             : 
    1696           0 :     if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC ||
    1697           0 :         mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR) {
    1698           0 :       mDrawTarget = mLayerManager->CreateOptimalMaskDrawTarget(mSize);
    1699           0 :       return mDrawTarget;
    1700             :     }
    1701             : 
    1702           0 :     MOZ_ASSERT(mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT);
    1703             : 
    1704           0 :     ShadowLayerForwarder* fwd = mLayerManager->AsShadowForwarder();
    1705           0 :     if (!fwd) {
    1706           0 :       return nullptr;
    1707             :     }
    1708             :     mTextureClient =
    1709           0 :       TextureClient::CreateForDrawing(fwd,
    1710             :                                       SurfaceFormat::A8,
    1711             :                                       mSize,
    1712             :                                       BackendSelector::Content,
    1713             :                                       TextureFlags::DISALLOW_BIGIMAGE,
    1714           0 :                                       TextureAllocationFlags::ALLOC_CLEAR_BUFFER);
    1715           0 :     if (!mTextureClient) {
    1716           0 :       return nullptr;
    1717             :     }
    1718             : 
    1719           0 :     mTextureClientLocked = mTextureClient->Lock(OpenMode::OPEN_READ_WRITE);
    1720           0 :     if (!mTextureClientLocked) {
    1721           0 :       return nullptr;
    1722             :     }
    1723             : 
    1724           0 :     mDrawTarget = mTextureClient->BorrowDrawTarget();
    1725           0 :     return mDrawTarget;
    1726             :   }
    1727             : 
    1728           0 :   already_AddRefed<ImageContainer> CreateImageAndImageContainer()
    1729             :   {
    1730           0 :     RefPtr<ImageContainer> container = mLayerManager->CreateImageContainer();
    1731           0 :     RefPtr<Image> image = CreateImage();
    1732             : 
    1733           0 :     if (!image) {
    1734           0 :       return nullptr;
    1735             :     }
    1736           0 :     container->SetCurrentImageInTransaction(image);
    1737             : 
    1738           0 :     return container.forget();
    1739             :   }
    1740             : 
    1741             : private:
    1742           0 :   already_AddRefed<Image> CreateImage()
    1743             :   {
    1744           0 :     if ((mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC ||
    1745           0 :          mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR) &&
    1746           0 :         mDrawTarget) {
    1747           0 :       RefPtr<SourceSurface> surface = mDrawTarget->Snapshot();
    1748           0 :       RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(mSize, surface);
    1749             :       // Disallow BIGIMAGE (splitting into multiple textures) for mask
    1750             :       // layer images
    1751           0 :       image->SetTextureFlags(TextureFlags::DISALLOW_BIGIMAGE);
    1752           0 :       return image.forget();
    1753             :     }
    1754             : 
    1755           0 :     if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT &&
    1756           0 :         mTextureClient &&
    1757           0 :         mDrawTarget) {
    1758             :       RefPtr<TextureWrapperImage> image =
    1759           0 :           new TextureWrapperImage(mTextureClient, gfx::IntRect(gfx::IntPoint(0, 0), mSize));
    1760           0 :       return image.forget();
    1761             :     }
    1762             : 
    1763           0 :     return nullptr;
    1764             :   }
    1765             : 
    1766             :   bool mTextureClientLocked;
    1767             :   gfx::IntSize mSize;
    1768             :   LayerManager* mLayerManager;
    1769             :   RefPtr<gfx::DrawTarget> mDrawTarget;
    1770             :   RefPtr<TextureClient> mTextureClient;
    1771             : };
    1772             : 
    1773             : /**
    1774             :   * Helper functions for getting user data and casting it to the correct type.
    1775             :   * aLayer is the layer where the user data is stored.
    1776             :   */
    1777           0 : MaskLayerUserData* GetMaskLayerUserData(Layer* aLayer)
    1778             : {
    1779           0 :   return static_cast<MaskLayerUserData*>(aLayer->GetUserData(&gMaskLayerUserData));
    1780             : }
    1781             : 
    1782         513 : PaintedDisplayItemLayerUserData* GetPaintedDisplayItemLayerUserData(Layer* aLayer)
    1783             : {
    1784             :   return static_cast<PaintedDisplayItemLayerUserData*>(
    1785         513 :     aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
    1786             : }
    1787             : 
    1788             : /* static */ void
    1789           0 : FrameLayerBuilder::Shutdown()
    1790             : {
    1791           0 :   if (gMaskLayerImageCache) {
    1792           0 :     delete gMaskLayerImageCache;
    1793           0 :     gMaskLayerImageCache = nullptr;
    1794             :   }
    1795           0 : }
    1796             : 
    1797             : void
    1798         187 : FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
    1799             :                         PaintedLayerData* aLayerData,
    1800             :                         const DisplayItemClip* aInactiveLayerClip)
    1801             : {
    1802         187 :   mDisplayListBuilder = aBuilder;
    1803         187 :   mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext();
    1804         187 :   if (mRootPresContext) {
    1805         187 :     mInitialDOMGeneration = mRootPresContext->GetDOMGeneration();
    1806             :   }
    1807         187 :   mContainingPaintedLayer = aLayerData;
    1808         187 :   mInactiveLayerClip = aInactiveLayerClip;
    1809         187 :   aManager->SetUserData(&gLayerManagerLayerBuilder, this);
    1810         187 : }
    1811             : 
    1812             : void
    1813           0 : FrameLayerBuilder::FlashPaint(gfxContext *aContext)
    1814             : {
    1815           0 :   float r = float(rand()) / RAND_MAX;
    1816           0 :   float g = float(rand()) / RAND_MAX;
    1817           0 :   float b = float(rand()) / RAND_MAX;
    1818           0 :   aContext->SetColor(Color(r, g, b, 0.4f));
    1819           0 :   aContext->Paint();
    1820           0 : }
    1821             : 
    1822             : DisplayItemData*
    1823        1901 : FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey)
    1824             : {
    1825        1901 :   const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
    1826        3031 :   for (uint32_t i = 0; i < array.Length(); i++) {
    1827        2868 :     DisplayItemData* item = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
    1828        4749 :     if (item->mDisplayItemKey == aKey &&
    1829        1881 :         item->mLayer->Manager() == mRetainingManager) {
    1830        1738 :       return item;
    1831             :     }
    1832             :   }
    1833         163 :   return nullptr;
    1834             : }
    1835             : 
    1836             : nsACString&
    1837           0 : AppendToString(nsACString& s, const nsIntRect& r,
    1838             :                const char* pfx="", const char* sfx="")
    1839             : {
    1840           0 :   s += pfx;
    1841           0 :   s += nsPrintfCString(
    1842             :     "(x=%d, y=%d, w=%d, h=%d)",
    1843           0 :     r.x, r.y, r.width, r.height);
    1844           0 :   return s += sfx;
    1845             : }
    1846             : 
    1847             : nsACString&
    1848           0 : AppendToString(nsACString& s, const nsIntRegion& r,
    1849             :                const char* pfx="", const char* sfx="")
    1850             : {
    1851           0 :   s += pfx;
    1852             : 
    1853           0 :   s += "< ";
    1854           0 :   for (auto iter = r.RectIter(); !iter.Done(); iter.Next()) {
    1855           0 :     AppendToString(s, iter.Get()) += "; ";
    1856             :   }
    1857           0 :   s += ">";
    1858             : 
    1859           0 :   return s += sfx;
    1860             : }
    1861             : 
    1862             : /**
    1863             :  * Invalidate aRegion in aLayer. aLayer is in the coordinate system
    1864             :  * *after* aTranslation has been applied, so we need to
    1865             :  * apply the inverse of that transform before calling InvalidateRegion.
    1866             :  */
    1867             : static void
    1868         202 : InvalidatePostTransformRegion(PaintedLayer* aLayer, const nsIntRegion& aRegion,
    1869             :                               const nsIntPoint& aTranslation)
    1870             : {
    1871             :   // Convert the region from the coordinates of the container layer
    1872             :   // (relative to the snapped top-left of the display list reference frame)
    1873             :   // to the PaintedLayer's own coordinates
    1874         404 :   nsIntRegion rgn = aRegion;
    1875         202 :   rgn.MoveBy(-aTranslation);
    1876         202 :   aLayer->InvalidateRegion(rgn);
    1877             : #ifdef MOZ_DUMP_PAINTING
    1878         202 :   if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    1879           0 :     nsAutoCString str;
    1880           0 :     AppendToString(str, rgn);
    1881           0 :     printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
    1882             :   }
    1883             : #endif
    1884         202 : }
    1885             : 
    1886             : static void
    1887           8 : InvalidatePostTransformRegion(PaintedLayer* aLayer, const nsRect& aRect,
    1888             :                               const DisplayItemClip& aClip,
    1889             :                               const nsIntPoint& aTranslation)
    1890             : {
    1891             :   PaintedDisplayItemLayerUserData* data =
    1892           8 :       static_cast<PaintedDisplayItemLayerUserData*>(aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
    1893             : 
    1894          16 :   nsRect rect = aClip.ApplyNonRoundedIntersection(aRect);
    1895             : 
    1896           8 :   nsIntRect pixelRect = rect.ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel);
    1897           8 :   InvalidatePostTransformRegion(aLayer, pixelRect, aTranslation);
    1898           8 : }
    1899             : 
    1900             : 
    1901             : static nsIntPoint
    1902         519 : GetTranslationForPaintedLayer(PaintedLayer* aLayer)
    1903             : {
    1904             :   PaintedDisplayItemLayerUserData* data =
    1905             :     static_cast<PaintedDisplayItemLayerUserData*>
    1906         519 :       (aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
    1907         519 :   NS_ASSERTION(data, "Must be a tracked painted layer!");
    1908             : 
    1909         519 :   return data->mTranslation;
    1910             : }
    1911             : 
    1912             : /**
    1913             :  * Some frames can have multiple, nested, retaining layer managers
    1914             :  * associated with them (normal manager, inactive managers, SVG effects).
    1915             :  * In these cases we store the 'outermost' LayerManager data property
    1916             :  * on the frame since we can walk down the chain from there.
    1917             :  *
    1918             :  * If one of these frames has just been destroyed, we will free the inner
    1919             :  * layer manager when removing the entry from mFramesWithLayers. Destroying
    1920             :  * the layer manager destroys the LayerManagerData and calls into
    1921             :  * the DisplayItemData destructor. If the inner layer manager had any
    1922             :  * items with the same frame, then we attempt to retrieve properties
    1923             :  * from the deleted frame.
    1924             :  *
    1925             :  * Cache the destroyed frame pointer here so we can avoid crashing in this case.
    1926             :  */
    1927             : 
    1928             : /* static */ void
    1929         126 : FrameLayerBuilder::RemoveFrameFromLayerManager(const nsIFrame* aFrame,
    1930             :                                                SmallPointerArray<DisplayItemData>& aArray)
    1931             : {
    1932         126 :   MOZ_RELEASE_ASSERT(!sDestroyedFrame);
    1933         126 :   sDestroyedFrame = aFrame;
    1934             : 
    1935             :   // Hold a reference to all the items so that they don't get
    1936             :   // deleted from under us.
    1937         252 :   nsTArray<RefPtr<DisplayItemData> > arrayCopy;
    1938         138 :   for (DisplayItemData* data : aArray) {
    1939          12 :     arrayCopy.AppendElement(data);
    1940             :   }
    1941             : 
    1942             : #ifdef DEBUG_DISPLAY_ITEM_DATA
    1943             :   if (aArray->Length()) {
    1944             :     LayerManagerData *rootData = aArray->ElementAt(0)->mParent;
    1945             :     while (rootData->mParent) {
    1946             :       rootData = rootData->mParent;
    1947             :     }
    1948             :     printf_stderr("Removing frame %p - dumping display data\n", aFrame);
    1949             :     rootData->Dump();
    1950             :   }
    1951             : #endif
    1952             : 
    1953         138 :   for (DisplayItemData* data : aArray) {
    1954          12 :     PaintedLayer* t = data->mLayer->AsPaintedLayer();
    1955          12 :     if (t) {
    1956             :       PaintedDisplayItemLayerUserData* paintedData =
    1957           9 :           static_cast<PaintedDisplayItemLayerUserData*>(t->GetUserData(&gPaintedDisplayItemLayerUserData));
    1958           9 :       if (paintedData && data->mGeometry) {
    1959          18 :         nsRegion old = data->mGeometry->ComputeInvalidationRegion();
    1960          18 :         nsIntRegion rgn = old.ScaleToOutsidePixels(paintedData->mXScale, paintedData->mYScale, paintedData->mAppUnitsPerDevPixel);
    1961           9 :         rgn.MoveBy(-GetTranslationForPaintedLayer(t));
    1962           9 :         paintedData->mRegionToInvalidate.Or(paintedData->mRegionToInvalidate, rgn);
    1963           9 :         paintedData->mRegionToInvalidate.SimplifyOutward(8);
    1964             :       }
    1965             :     }
    1966             : 
    1967          12 :     data->mParent->mDisplayItems.RemoveEntry(data);
    1968             :   }
    1969             : 
    1970         126 :   arrayCopy.Clear();
    1971         126 :   sDestroyedFrame = nullptr;
    1972         126 : }
    1973             : 
    1974             : void
    1975         167 : FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
    1976             : {
    1977         167 :   mRetainingManager = aManager;
    1978             :   LayerManagerData* data = static_cast<LayerManagerData*>
    1979         167 :     (aManager->GetUserData(&gLayerManagerUserData));
    1980         167 :   if (data) {
    1981         155 :     mInvalidateAllLayers = data->mInvalidateAllLayers;
    1982             :   } else {
    1983          12 :     data = new LayerManagerData(aManager);
    1984          12 :     aManager->SetUserData(&gLayerManagerUserData, data);
    1985             :   }
    1986         167 : }
    1987             : 
    1988             : void
    1989           3 : FrameLayerBuilder::StoreOptimizedLayerForFrame(nsDisplayItem* aItem, Layer* aLayer)
    1990             : {
    1991           3 :   if (!mRetainingManager) {
    1992           0 :     return;
    1993             :   }
    1994             : 
    1995           3 :   DisplayItemData* data = GetDisplayItemDataForManager(aItem, aLayer->Manager());
    1996           3 :   NS_ASSERTION(data, "Must have already stored data for this item!");
    1997           3 :   data->mOptLayer = aLayer;
    1998           3 :   data->mItem = nullptr;
    1999             : }
    2000             : 
    2001             : void
    2002          74 : FrameLayerBuilder::DidEndTransaction()
    2003             : {
    2004          74 :   GetMaskLayerImageCache()->Sweep();
    2005          74 : }
    2006             : 
    2007             : void
    2008         187 : FrameLayerBuilder::WillEndTransaction()
    2009             : {
    2010         187 :   if (!mRetainingManager) {
    2011          20 :     return;
    2012             :   }
    2013             : 
    2014             :   // We need to save the data we'll need to support retaining.
    2015             :   LayerManagerData* data = static_cast<LayerManagerData*>
    2016         167 :     (mRetainingManager->GetUserData(&gLayerManagerUserData));
    2017         167 :   NS_ASSERTION(data, "Must have data!");
    2018             : 
    2019             :   // Update all the frames that used to have layers.
    2020        1635 :   for (auto iter = data->mDisplayItems.Iter(); !iter.Done(); iter.Next()) {
    2021        1468 :     DisplayItemData* data = iter.Get()->GetKey();
    2022        1468 :     if (!data->mUsed) {
    2023             :       // This item was visible, but isn't anymore.
    2024           9 :       PaintedLayer* t = data->mLayer->AsPaintedLayer();
    2025           9 :       if (t && data->mGeometry) {
    2026             : #ifdef MOZ_DUMP_PAINTING
    2027           8 :         if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    2028           0 :           printf_stderr("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", data->mDisplayItemKey, data->mFrameList[0], t);
    2029             :         }
    2030             : #endif
    2031           8 :         InvalidatePostTransformRegion(t,
    2032             :                                       data->mGeometry->ComputeInvalidationRegion(),
    2033             :                                       data->mClip,
    2034          16 :                                       GetLastPaintOffset(t));
    2035             :       }
    2036             : 
    2037           9 :       data->ClearAnimationCompositorState();
    2038           9 :       iter.Remove();
    2039             :     } else {
    2040        1459 :       ComputeGeometryChangeForItem(data);
    2041             :     }
    2042             :   }
    2043             : 
    2044         167 :   data->mInvalidateAllLayers = false;
    2045             : }
    2046             : 
    2047             : /* static */ DisplayItemData*
    2048        1748 : FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem,
    2049             :                                                 LayerManager* aManager)
    2050             : {
    2051             :   const SmallPointerArray<DisplayItemData>& array =
    2052        1748 :     aItem->Frame()->DisplayItemData();
    2053        2842 :   for (uint32_t i = 0; i < array.Length(); i++) {
    2054        2745 :     DisplayItemData* item = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
    2055        4680 :     if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
    2056        1935 :         item->mLayer->Manager() == aManager) {
    2057        1651 :       return item;
    2058             :     }
    2059             :   }
    2060          97 :   return nullptr;
    2061             : }
    2062             : 
    2063             : bool
    2064          37 : FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
    2065             : {
    2066             :   const SmallPointerArray<DisplayItemData>& array =
    2067          37 :     aFrame->DisplayItemData();
    2068          57 :   for (uint32_t i = 0; i < array.Length(); i++) {
    2069          49 :     if (DisplayItemData::AssertDisplayItemData(array.ElementAt(i))->mDisplayItemKey == aDisplayItemKey) {
    2070          29 :       return true;
    2071             :     }
    2072             :   }
    2073           8 :   return false;
    2074             : }
    2075             : 
    2076             : void
    2077          15 : FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
    2078             : {
    2079          15 :   const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
    2080             : 
    2081          30 :   for (uint32_t i = 0; i < array.Length(); i++) {
    2082          15 :     DisplayItemData* data = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
    2083          15 :     if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO) {
    2084          15 :       aCallback(aFrame, data);
    2085             :     }
    2086             :   }
    2087          15 : }
    2088             : 
    2089             : DisplayItemData*
    2090        2017 : FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey)
    2091             : {
    2092             :   // If we need to build a new layer tree, then just refuse to recycle
    2093             :   // anything.
    2094        2017 :   if (!mRetainingManager || mInvalidateAllLayers)
    2095         142 :     return nullptr;
    2096             : 
    2097        1875 :   DisplayItemData *data = GetDisplayItemData(aFrame, aDisplayItemKey);
    2098             : 
    2099        1875 :   if (data && data->mLayer->Manager() == mRetainingManager) {
    2100        1714 :     return data;
    2101             :   }
    2102         161 :   return nullptr;
    2103             : }
    2104             : 
    2105             : Layer*
    2106        1942 : FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem,
    2107             :                                   nsDisplayItemGeometry** aOldGeometry,
    2108             :                                   DisplayItemClip** aOldClip)
    2109             : {
    2110        1942 :   uint32_t key = aItem->GetPerFrameKey();
    2111        1942 :   nsIFrame* frame = aItem->Frame();
    2112             : 
    2113        1942 :   DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
    2114        1942 :   if (oldData) {
    2115        1641 :     if (aOldGeometry) {
    2116        1217 :       *aOldGeometry = oldData->mGeometry.get();
    2117             :     }
    2118        1641 :     if (aOldClip) {
    2119        1348 :       *aOldClip = &oldData->mClip;
    2120             :     }
    2121        1641 :     return oldData->mLayer;
    2122             :   }
    2123             : 
    2124         301 :   return nullptr;
    2125             : }
    2126             : 
    2127             : void
    2128          49 : FrameLayerBuilder::ClearCachedGeometry(nsDisplayItem* aItem)
    2129             : {
    2130          49 :   uint32_t key = aItem->GetPerFrameKey();
    2131          49 :   nsIFrame* frame = aItem->Frame();
    2132             : 
    2133          49 :   DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
    2134          49 :   if (oldData) {
    2135          49 :     oldData->mGeometry = nullptr;
    2136             :   }
    2137          49 : }
    2138             : 
    2139             : /* static */ Layer*
    2140           0 : FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
    2141             : {
    2142           0 :   const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
    2143             : 
    2144           0 :   for (uint32_t i = 0; i < array.Length(); i++) {
    2145           0 :     DisplayItemData *data = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
    2146             : 
    2147           0 :     if (data->mDisplayItemKey == aDisplayItemKey) {
    2148           0 :       return data->mLayer;
    2149             :     }
    2150             :   }
    2151           0 :   return nullptr;
    2152             : }
    2153             : 
    2154             : // Reset state that should not persist when a layer is recycled.
    2155             : static void
    2156         318 : ResetLayerStateForRecycling(Layer* aLayer) {
    2157             :   // Currently, this clears the mask layer and ancestor mask layers.
    2158             :   // Other cleanup may be added here.
    2159         318 :   aLayer->SetMaskLayer(nullptr);
    2160         318 :   aLayer->SetAncestorMaskLayers({});
    2161         318 : }
    2162             : 
    2163             : already_AddRefed<ColorLayer>
    2164           3 : ContainerState::CreateOrRecycleColorLayer(PaintedLayer *aPainted)
    2165             : {
    2166             :   PaintedDisplayItemLayerUserData* data =
    2167           3 :       static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
    2168           6 :   RefPtr<ColorLayer> layer = data->mColorLayer;
    2169           3 :   if (layer) {
    2170           1 :     ResetLayerStateForRecycling(layer);
    2171           1 :     layer->ClearExtraDumpInfo();
    2172             :   } else {
    2173             :     // Create a new layer
    2174           2 :     layer = mManager->CreateColorLayer();
    2175           2 :     if (!layer)
    2176           0 :       return nullptr;
    2177             :     // Mark this layer as being used for painting display items
    2178           2 :     data->mColorLayer = layer;
    2179           2 :     layer->SetUserData(&gColorLayerUserData, nullptr);
    2180             : 
    2181             :     // Remove other layer types we might have stored for this PaintedLayer
    2182           2 :     data->mImageLayer = nullptr;
    2183             :   }
    2184           3 :   return layer.forget();
    2185             : }
    2186             : 
    2187             : already_AddRefed<ImageLayer>
    2188           0 : ContainerState::CreateOrRecycleImageLayer(PaintedLayer *aPainted)
    2189             : {
    2190             :   PaintedDisplayItemLayerUserData* data =
    2191           0 :       static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
    2192           0 :   RefPtr<ImageLayer> layer = data->mImageLayer;
    2193           0 :   if (layer) {
    2194           0 :     ResetLayerStateForRecycling(layer);
    2195           0 :     layer->ClearExtraDumpInfo();
    2196             :   } else {
    2197             :     // Create a new layer
    2198           0 :     layer = mManager->CreateImageLayer();
    2199           0 :     if (!layer)
    2200           0 :       return nullptr;
    2201             :     // Mark this layer as being used for painting display items
    2202           0 :     data->mImageLayer = layer;
    2203           0 :     layer->SetUserData(&gImageLayerUserData, nullptr);
    2204             : 
    2205             :     // Remove other layer types we might have stored for this PaintedLayer
    2206           0 :     data->mColorLayer = nullptr;
    2207             :   }
    2208           0 :   return layer.forget();
    2209             : }
    2210             : 
    2211             : already_AddRefed<ImageLayer>
    2212           0 : ContainerState::CreateOrRecycleMaskImageLayerFor(const MaskLayerKey& aKey,
    2213             :                                                  const std::function<void(Layer* aLayer)>& aSetUserData)
    2214             : {
    2215           0 :   RefPtr<ImageLayer> result = mRecycledMaskImageLayers.Get(aKey);
    2216           0 :   if (result) {
    2217           0 :     mRecycledMaskImageLayers.Remove(aKey);
    2218           0 :     aKey.mLayer->ClearExtraDumpInfo();
    2219             :     // XXX if we use clip on mask layers, null it out here
    2220             :   } else {
    2221             :     // Create a new layer
    2222           0 :     result = mManager->CreateImageLayer();
    2223           0 :     if (!result)
    2224           0 :       return nullptr;
    2225           0 :     aSetUserData(result);
    2226             :   }
    2227             : 
    2228           0 :   return result.forget();
    2229             : }
    2230             : 
    2231             : static const double SUBPIXEL_OFFSET_EPSILON = 0.02;
    2232             : 
    2233             : /**
    2234             :  * This normally computes NSToIntRoundUp(aValue). However, if that would
    2235             :  * give a residual near 0.5 while aOldResidual is near -0.5, or
    2236             :  * it would give a residual near -0.5 while aOldResidual is near 0.5, then
    2237             :  * instead we return the integer in the other direction so that the residual
    2238             :  * is close to aOldResidual.
    2239             :  */
    2240             : static int32_t
    2241         516 : RoundToMatchResidual(double aValue, double aOldResidual)
    2242             : {
    2243         516 :   int32_t v = NSToIntRoundUp(aValue);
    2244         516 :   double residual = aValue - v;
    2245         516 :   if (aOldResidual < 0) {
    2246           0 :     if (residual > 0 && fabs(residual - 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
    2247             :       // Round up instead
    2248           0 :       return int32_t(ceil(aValue));
    2249             :     }
    2250         516 :   } else if (aOldResidual > 0) {
    2251           0 :     if (residual < 0 && fabs(residual + 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
    2252             :       // Round down instead
    2253           0 :       return int32_t(floor(aValue));
    2254             :     }
    2255             :   }
    2256         516 :   return v;
    2257             : }
    2258             : 
    2259             : static void
    2260         145 : ResetScrollPositionForLayerPixelAlignment(AnimatedGeometryRoot* aAnimatedGeometryRoot)
    2261             : {
    2262         145 :   nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
    2263         145 :   if (sf) {
    2264           1 :     sf->ResetScrollPositionForLayerPixelAlignment();
    2265             :   }
    2266         145 : }
    2267             : 
    2268             : static void
    2269           0 : InvalidateEntirePaintedLayer(PaintedLayer* aLayer, AnimatedGeometryRoot* aAnimatedGeometryRoot, const char *aReason)
    2270             : {
    2271             : #ifdef MOZ_DUMP_PAINTING
    2272           0 :   if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    2273           0 :     printf_stderr("Invalidating entire layer %p: %s\n", aLayer, aReason);
    2274             :   }
    2275             : #endif
    2276           0 :   aLayer->InvalidateWholeLayer();
    2277           0 :   aLayer->SetInvalidRectToVisibleRegion();
    2278           0 :   ResetScrollPositionForLayerPixelAlignment(aAnimatedGeometryRoot);
    2279           0 : }
    2280             : 
    2281             : LayerManager::PaintedLayerCreationHint
    2282         334 : ContainerState::GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot)
    2283             : {
    2284             :   // Check whether the layer will be scrollable. This is used as a hint to
    2285             :   // influence whether tiled layers are used or not.
    2286             : 
    2287             :   // Check creation hint inherited from our parent.
    2288         334 :   if (mParameters.mLayerCreationHint == LayerManager::SCROLLABLE) {
    2289           0 :     return LayerManager::SCROLLABLE;
    2290             :   }
    2291             : 
    2292             :   // Check whether there's any active scroll frame on the animated geometry
    2293             :   // root chain.
    2294         334 :   for (AnimatedGeometryRoot* agr = aAnimatedGeometryRoot;
    2295         334 :        agr && agr != mContainerAnimatedGeometryRoot;
    2296           0 :        agr = agr->mParentAGR) {
    2297           2 :     nsIFrame* fParent = nsLayoutUtils::GetCrossDocParentFrame(*agr);
    2298           2 :     if (!fParent) {
    2299           0 :       break;
    2300             :     }
    2301           2 :     nsIScrollableFrame* scrollable = do_QueryFrame(fParent);
    2302           2 :     if (scrollable) {
    2303           2 :       return LayerManager::SCROLLABLE;
    2304             :     }
    2305             :   }
    2306         332 :   return LayerManager::NONE;
    2307             : }
    2308             : 
    2309             : already_AddRefed<PaintedLayer>
    2310         232 : ContainerState::AttemptToRecyclePaintedLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    2311             :                                              nsDisplayItem* aItem,
    2312             :                                              const nsPoint& aTopLeft)
    2313             : {
    2314         232 :   Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem);
    2315         232 :   if (!oldLayer || !oldLayer->AsPaintedLayer()) {
    2316         119 :     return nullptr;
    2317             :   }
    2318             : 
    2319         113 :   if (!mPaintedLayersAvailableForRecycling.EnsureRemoved(oldLayer->AsPaintedLayer())) {
    2320             :     // Not found.
    2321           0 :     return nullptr;
    2322             :   }
    2323             : 
    2324             :   // Try to recycle the layer.
    2325         226 :   RefPtr<PaintedLayer> layer = oldLayer->AsPaintedLayer();
    2326             : 
    2327             :   // Check if the layer hint has changed and whether or not the layer should
    2328             :   // be recreated because of it.
    2329         113 :   if (!layer->IsOptimizedFor(GetLayerCreationHint(aAnimatedGeometryRoot))) {
    2330           0 :     return nullptr;
    2331             :   }
    2332             : 
    2333         113 :   bool didResetScrollPositionForLayerPixelAlignment = false;
    2334             :   PaintedDisplayItemLayerUserData* data =
    2335         113 :     RecyclePaintedLayer(layer, aAnimatedGeometryRoot,
    2336         113 :                         didResetScrollPositionForLayerPixelAlignment);
    2337         113 :   PreparePaintedLayerForUse(layer, data, aAnimatedGeometryRoot, aItem->ReferenceFrame(),
    2338             :                             aTopLeft,
    2339         113 :                             didResetScrollPositionForLayerPixelAlignment);
    2340             : 
    2341         113 :   return layer.forget();
    2342             : }
    2343             : 
    2344             : already_AddRefed<PaintedLayer>
    2345         145 : ContainerState::CreatePaintedLayer(PaintedLayerData* aData)
    2346             : {
    2347             :   LayerManager::PaintedLayerCreationHint creationHint =
    2348         145 :     GetLayerCreationHint(aData->mAnimatedGeometryRoot);
    2349             : 
    2350             :   // Create a new painted layer
    2351         290 :   RefPtr<PaintedLayer> layer = mManager->CreatePaintedLayerWithHint(creationHint);
    2352         145 :   if (!layer) {
    2353           0 :     return nullptr;
    2354             :   }
    2355             : 
    2356             :   // Mark this layer as being used for painting display items
    2357         145 :   PaintedDisplayItemLayerUserData* userData = new PaintedDisplayItemLayerUserData();
    2358         145 :   userData->mDisabledAlpha =
    2359         145 :     mParameters.mDisableSubpixelAntialiasingInDescendants;
    2360         145 :   layer->SetUserData(&gPaintedDisplayItemLayerUserData, userData);
    2361         145 :   ResetScrollPositionForLayerPixelAlignment(aData->mAnimatedGeometryRoot);
    2362             : 
    2363         145 :   PreparePaintedLayerForUse(layer, userData, aData->mAnimatedGeometryRoot,
    2364             :                             aData->mReferenceFrame,
    2365         145 :                             aData->mAnimatedGeometryRootOffset, true);
    2366             : 
    2367         145 :   return layer.forget();
    2368             : }
    2369             : 
    2370             : PaintedDisplayItemLayerUserData*
    2371         113 : ContainerState::RecyclePaintedLayer(PaintedLayer* aLayer,
    2372             :                                     AnimatedGeometryRoot* aAnimatedGeometryRoot,
    2373             :                                     bool& didResetScrollPositionForLayerPixelAlignment)
    2374             : {
    2375             :   // Clear clip rect and mask layer so we don't accidentally stay clipped.
    2376             :   // We will reapply any necessary clipping.
    2377         113 :   ResetLayerStateForRecycling(aLayer);
    2378         113 :   aLayer->ClearExtraDumpInfo();
    2379             : 
    2380             :   PaintedDisplayItemLayerUserData* data =
    2381             :     static_cast<PaintedDisplayItemLayerUserData*>(
    2382         113 :       aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
    2383         113 :   NS_ASSERTION(data, "Recycled PaintedLayers must have user data");
    2384             : 
    2385             :   // This gets called on recycled PaintedLayers that are going to be in the
    2386             :   // final layer tree, so it's a convenient time to invalidate the
    2387             :   // content that changed where we don't know what PaintedLayer it belonged
    2388             :   // to, or if we need to invalidate the entire layer, we can do that.
    2389             :   // This needs to be done before we update the PaintedLayer to its new
    2390             :   // transform. See nsGfxScrollFrame::InvalidateInternal, where
    2391             :   // we ensure that mInvalidPaintedContent is updated according to the
    2392             :   // scroll position as of the most recent paint.
    2393         339 :   if (!FuzzyEqual(data->mXScale, mParameters.mXScale, 0.00001f) ||
    2394         226 :       !FuzzyEqual(data->mYScale, mParameters.mYScale, 0.00001f) ||
    2395         113 :       data->mAppUnitsPerDevPixel != mAppUnitsPerDevPixel) {
    2396             : #ifdef MOZ_DUMP_PAINTING
    2397           0 :   if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    2398           0 :     printf_stderr("Recycled layer %p changed scale\n", aLayer);
    2399             :   }
    2400             : #endif
    2401           0 :     InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "recycled layer changed state");
    2402           0 :     didResetScrollPositionForLayerPixelAlignment = true;
    2403             :   }
    2404         113 :   if (!data->mRegionToInvalidate.IsEmpty()) {
    2405             : #ifdef MOZ_DUMP_PAINTING
    2406           3 :     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    2407           0 :       printf_stderr("Invalidating deleted frame content from layer %p\n", aLayer);
    2408             :     }
    2409             : #endif
    2410           3 :     aLayer->InvalidateRegion(data->mRegionToInvalidate);
    2411             : #ifdef MOZ_DUMP_PAINTING
    2412           3 :     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    2413           0 :       nsAutoCString str;
    2414           0 :       AppendToString(str, data->mRegionToInvalidate);
    2415           0 :       printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
    2416             :     }
    2417             : #endif
    2418           3 :     data->mRegionToInvalidate.SetEmpty();
    2419             :   }
    2420         113 :   return data;
    2421             : }
    2422             : 
    2423             : void
    2424         258 : ContainerState::PreparePaintedLayerForUse(PaintedLayer* aLayer,
    2425             :                                           PaintedDisplayItemLayerUserData* aData,
    2426             :                                           AnimatedGeometryRoot* aAnimatedGeometryRoot,
    2427             :                                           const nsIFrame* aReferenceFrame,
    2428             :                                           const nsPoint& aTopLeft,
    2429             :                                           bool didResetScrollPositionForLayerPixelAlignment)
    2430             : {
    2431         258 :   aData->mXScale = mParameters.mXScale;
    2432         258 :   aData->mYScale = mParameters.mYScale;
    2433         258 :   aData->mLastAnimatedGeometryRootOrigin = aData->mAnimatedGeometryRootOrigin;
    2434         258 :   aData->mAnimatedGeometryRootOrigin = aTopLeft;
    2435         258 :   aData->mAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
    2436         258 :   aLayer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation());
    2437             : 
    2438         258 :   mLayerBuilder->SavePreviousDataForLayer(aLayer, aData->mMaskClipCount);
    2439             : 
    2440             :   // Set up transform so that 0,0 in the PaintedLayer corresponds to the
    2441             :   // (pixel-snapped) top-left of the aAnimatedGeometryRoot.
    2442         258 :   nsPoint offset = (*aAnimatedGeometryRoot)->GetOffsetToCrossDoc(aReferenceFrame);
    2443         258 :   nscoord appUnitsPerDevPixel = (*aAnimatedGeometryRoot)->PresContext()->AppUnitsPerDevPixel();
    2444             :   gfxPoint scaledOffset(
    2445         258 :       NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel)*mParameters.mXScale,
    2446         516 :       NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel)*mParameters.mYScale);
    2447             :   // We call RoundToMatchResidual here so that the residual after rounding
    2448             :   // is close to aData->mAnimatedGeometryRootPosition if possible.
    2449             :   nsIntPoint pixOffset(RoundToMatchResidual(scaledOffset.x, aData->mAnimatedGeometryRootPosition.x),
    2450         258 :                        RoundToMatchResidual(scaledOffset.y, aData->mAnimatedGeometryRootPosition.y));
    2451         258 :   aData->mTranslation = pixOffset;
    2452         258 :   pixOffset += mParameters.mOffset;
    2453         258 :   Matrix matrix = Matrix::Translation(pixOffset.x, pixOffset.y);
    2454         258 :   aLayer->SetBaseTransform(Matrix4x4::From2D(matrix));
    2455             : 
    2456         258 :   aData->mVisibilityComputedRegion.SetEmpty();
    2457             : 
    2458             :   // Calculate exact position of the top-left of the active scrolled root.
    2459             :   // This might not be 0,0 due to the snapping in ScaleToNearestPixels.
    2460         258 :   gfxPoint animatedGeometryRootTopLeft = scaledOffset - ThebesPoint(matrix.GetTranslation()) + mParameters.mOffset;
    2461             :   const bool disableAlpha =
    2462         258 :     mParameters.mDisableSubpixelAntialiasingInDescendants;
    2463         258 :   if (aData->mDisabledAlpha != disableAlpha) {
    2464           0 :     aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
    2465           0 :     InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "change of subpixel-AA");
    2466           0 :     aData->mDisabledAlpha = disableAlpha;
    2467           0 :     return;
    2468             :   }
    2469             : 
    2470             :   // FIXME: Temporary workaround for bug 681192 and bug 724786.
    2471             : #ifndef MOZ_WIDGET_ANDROID
    2472             :   // If it has changed, then we need to invalidate the entire layer since the
    2473             :   // pixels in the layer buffer have the content at a (subpixel) offset
    2474             :   // from what we need.
    2475         258 :   if (!animatedGeometryRootTopLeft.WithinEpsilonOf(aData->mAnimatedGeometryRootPosition, SUBPIXEL_OFFSET_EPSILON)) {
    2476           0 :     aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
    2477           0 :     InvalidateEntirePaintedLayer(aLayer, aAnimatedGeometryRoot, "subpixel offset");
    2478         258 :   } else if (didResetScrollPositionForLayerPixelAlignment) {
    2479         145 :     aData->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
    2480             :   }
    2481             : #else
    2482             :   Unused << didResetScrollPositionForLayerPixelAlignment;
    2483             : #endif
    2484             : }
    2485             : 
    2486             : #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
    2487             : /**
    2488             :  * Returns the appunits per dev pixel for the item's frame
    2489             :  */
    2490             : static int32_t
    2491        2662 : AppUnitsPerDevPixel(nsDisplayItem* aItem)
    2492             : {
    2493             :   // The underlying frame for zoom items is the root frame of the subdocument.
    2494             :   // But zoom display items report their bounds etc using the parent document's
    2495             :   // APD because zoom items act as a conversion layer between the two different
    2496             :   // APDs.
    2497        2662 :   if (aItem->GetType() == nsDisplayItem::TYPE_ZOOM) {
    2498           0 :     return static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
    2499             :   }
    2500        2662 :   return aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
    2501             : }
    2502             : #endif
    2503             : 
    2504             : /**
    2505             :  * Set the visible region for aLayer.
    2506             :  * aOuterVisibleRegion is the visible region relative to the parent layer.
    2507             :  * aLayerContentsVisibleRect, if non-null, is a rectangle in the layer's
    2508             :  * own coordinate system to which the layer's visible region is restricted.
    2509             :  * Consumes *aOuterVisibleRegion.
    2510             :  */
    2511             : static void
    2512         480 : SetOuterVisibleRegion(Layer* aLayer, nsIntRegion* aOuterVisibleRegion,
    2513             :                       const nsIntRect* aLayerContentsVisibleRect = nullptr,
    2514             :                       bool aOuterUntransformed = false)
    2515             : {
    2516         480 :   Matrix4x4 transform = aLayer->GetTransform();
    2517         480 :   Matrix transform2D;
    2518         480 :   if (aOuterUntransformed) {
    2519           0 :     if (aLayerContentsVisibleRect) {
    2520             :       aOuterVisibleRegion->And(*aOuterVisibleRegion,
    2521           0 :                                *aLayerContentsVisibleRect);
    2522             :     }
    2523         480 :   } else if (transform.Is2D(&transform2D) && !transform2D.HasNonIntegerTranslation()) {
    2524         480 :     aOuterVisibleRegion->MoveBy(-int(transform2D._31), -int(transform2D._32));
    2525         480 :     if (aLayerContentsVisibleRect) {
    2526          52 :       aOuterVisibleRegion->And(*aOuterVisibleRegion, *aLayerContentsVisibleRect);
    2527             :     }
    2528             :   } else {
    2529           0 :     nsIntRect outerRect = aOuterVisibleRegion->GetBounds();
    2530             :     // if 'transform' is not invertible, then nothing will be displayed
    2531             :     // for the layer, so it doesn't really matter what we do here
    2532           0 :     Rect outerVisible(outerRect.x, outerRect.y, outerRect.width, outerRect.height);
    2533           0 :     transform.Invert();
    2534             : 
    2535             :     Rect layerContentsVisible(-float(INT32_MAX) / 2, -float(INT32_MAX) / 2,
    2536           0 :                               float(INT32_MAX), float(INT32_MAX));
    2537           0 :     if (aLayerContentsVisibleRect) {
    2538           0 :       NS_ASSERTION(aLayerContentsVisibleRect->width >= 0 &&
    2539             :                    aLayerContentsVisibleRect->height >= 0,
    2540             :                    "Bad layer contents rectangle");
    2541             :       // restrict to aLayerContentsVisibleRect before call GfxRectToIntRect,
    2542             :       // in case layerVisible is extremely large (as it can be when
    2543             :       // projecting through the inverse of a 3D transform)
    2544           0 :       layerContentsVisible = Rect(
    2545           0 :           aLayerContentsVisibleRect->x, aLayerContentsVisibleRect->y,
    2546           0 :           aLayerContentsVisibleRect->width, aLayerContentsVisibleRect->height);
    2547             :     }
    2548           0 :     gfxRect layerVisible = ThebesRect(transform.ProjectRectBounds(outerVisible, layerContentsVisible));
    2549           0 :     layerVisible.RoundOut();
    2550           0 :     nsIntRect visRect;
    2551           0 :     if (gfxUtils::GfxRectToIntRect(layerVisible, &visRect)) {
    2552           0 :       *aOuterVisibleRegion = visRect;
    2553             :     } else  {
    2554           0 :       aOuterVisibleRegion->SetEmpty();
    2555             :     }
    2556             :   }
    2557             : 
    2558         480 :   aLayer->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(*aOuterVisibleRegion));
    2559         480 : }
    2560             : 
    2561             : void
    2562         337 : ContainerState::SetOuterVisibleRegionForLayer(Layer* aLayer,
    2563             :                                               const nsIntRegion& aOuterVisibleRegion,
    2564             :                                               const nsIntRect* aLayerContentsVisibleRect,
    2565             :                                               bool aOuterUntransformed) const
    2566             : {
    2567         674 :   nsIntRegion visRegion = aOuterVisibleRegion;
    2568         337 :   if (!aOuterUntransformed) {
    2569         337 :     visRegion.MoveBy(mParameters.mOffset);
    2570             :   }
    2571         337 :   SetOuterVisibleRegion(aLayer, &visRegion, aLayerContentsVisibleRect,
    2572         337 :                         aOuterUntransformed);
    2573         337 : }
    2574             : 
    2575             : nscolor
    2576          43 : ContainerState::FindOpaqueBackgroundColorInLayer(const PaintedLayerData* aData,
    2577             :                                                  const nsIntRect& aRect,
    2578             :                                                  bool* aOutIntersectsLayer) const
    2579             : {
    2580          43 :   *aOutIntersectsLayer = true;
    2581             : 
    2582             :   // Scan the candidate's display items.
    2583          43 :   nsIntRect deviceRect = aRect;
    2584          86 :   nsRect appUnitRect = ToAppUnits(deviceRect, mAppUnitsPerDevPixel);
    2585          43 :   appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
    2586             : 
    2587          77 :   for (auto& assignedItem : Reversed(aData->mAssignedDisplayItems)) {
    2588          77 :     nsDisplayItem* item = assignedItem.mItem;
    2589             :     bool snap;
    2590          77 :     nsRect bounds = item->GetBounds(mBuilder, &snap);
    2591          77 :     if (snap && mSnappingEnabled) {
    2592          75 :       nsIntRect snappedBounds = ScaleToNearestPixels(bounds);
    2593          75 :       if (!snappedBounds.Intersects(deviceRect))
    2594          34 :         continue;
    2595             : 
    2596          41 :       if (!snappedBounds.Contains(deviceRect))
    2597          17 :         return NS_RGBA(0,0,0,0);
    2598             : 
    2599             :     } else {
    2600             :       // The layer's visible rect is already (close enough to) pixel
    2601             :       // aligned, so no need to round out and in here.
    2602           2 :       if (!bounds.Intersects(appUnitRect))
    2603           0 :         continue;
    2604             : 
    2605           2 :       if (!bounds.Contains(appUnitRect))
    2606           0 :         return NS_RGBA(0,0,0,0);
    2607             :     }
    2608             : 
    2609          26 :     if (item->IsInvisibleInRect(appUnitRect)) {
    2610           0 :       continue;
    2611             :     }
    2612             : 
    2613          26 :     if (assignedItem.mClip.IsRectAffectedByClip(deviceRect,
    2614          26 :                                                 mParameters.mXScale,
    2615          26 :                                                 mParameters.mYScale,
    2616          26 :                                                 mAppUnitsPerDevPixel)) {
    2617           0 :       return NS_RGBA(0,0,0,0);
    2618             :     }
    2619             : 
    2620          52 :     Maybe<nscolor> color = item->IsUniform(mBuilder);
    2621          26 :     if (color && NS_GET_A(*color) == 255)
    2622          24 :       return *color;
    2623             : 
    2624           2 :     return NS_RGBA(0,0,0,0);
    2625             :   }
    2626             : 
    2627           0 :   *aOutIntersectsLayer = false;
    2628           0 :   return NS_RGBA(0,0,0,0);
    2629             : }
    2630             : 
    2631             : nscolor
    2632         198 : PaintedLayerDataNode::FindOpaqueBackgroundColor(const nsIntRegion& aTargetVisibleRegion,
    2633             :                                                 int32_t aUnderIndex) const
    2634             : {
    2635         198 :   if (aUnderIndex == ABOVE_TOP) {
    2636          74 :     aUnderIndex = mPaintedLayerDataStack.Length();
    2637             :   }
    2638         218 :   for (int32_t i = aUnderIndex - 1; i >= 0; --i) {
    2639          76 :     const PaintedLayerData* candidate = &mPaintedLayerDataStack[i];
    2640          76 :     if (candidate->VisibleAboveRegionIntersects(aTargetVisibleRegion)) {
    2641             :       // Some non-PaintedLayer content between target and candidate; this is
    2642             :       // hopeless
    2643          69 :       return NS_RGBA(0,0,0,0);
    2644             :     }
    2645             : 
    2646          63 :     if (!candidate->VisibleRegionIntersects(aTargetVisibleRegion)) {
    2647             :       // The layer doesn't intersect our target, ignore it and move on
    2648          40 :       continue;
    2649             :     }
    2650             : 
    2651          43 :     bool intersectsLayer = true;
    2652          43 :     nsIntRect rect = aTargetVisibleRegion.GetBounds();
    2653          43 :     nscolor color = mTree.ContState().FindOpaqueBackgroundColorInLayer(
    2654          43 :                                         candidate, rect, &intersectsLayer);
    2655          43 :     if (!intersectsLayer) {
    2656           0 :       continue;
    2657             :     }
    2658          43 :     return color;
    2659             :   }
    2660         568 :   if (mAllDrawingAboveBackground ||
    2661         568 :       !mVisibleAboveBackgroundRegion.Intersect(aTargetVisibleRegion).IsEmpty()) {
    2662             :     // Some non-PaintedLayer content is between this node's background and target.
    2663           0 :     return NS_RGBA(0,0,0,0);
    2664             :   }
    2665         142 :   return FindOpaqueBackgroundColorInParentNode();
    2666             : }
    2667             : 
    2668             : nscolor
    2669           0 : PaintedLayerDataNode::FindOpaqueBackgroundColorCoveringEverything() const
    2670             : {
    2671           0 :   if (!mPaintedLayerDataStack.IsEmpty() ||
    2672           0 :       mAllDrawingAboveBackground ||
    2673           0 :       !mVisibleAboveBackgroundRegion.IsEmpty()) {
    2674           0 :     return NS_RGBA(0,0,0,0);
    2675             :   }
    2676           0 :   return FindOpaqueBackgroundColorInParentNode();
    2677             : }
    2678             : 
    2679             : nscolor
    2680         142 : PaintedLayerDataNode::FindOpaqueBackgroundColorInParentNode() const
    2681             : {
    2682         142 :   if (mParent) {
    2683           0 :     if (mHasClip) {
    2684             :       // Check whether our parent node has uniform content behind our whole
    2685             :       // clip.
    2686             :       // There's one tricky case here: If our parent node is also a scrollable,
    2687             :       // and is currently scrolled in such a way that this inner one is
    2688             :       // clipped by it, then it's not really clear how we should determine
    2689             :       // whether we have a uniform background in the parent: There might be
    2690             :       // non-uniform content in the parts that our scroll port covers in the
    2691             :       // parent and that are currently outside the parent's clip.
    2692             :       // For now, we'll fail to pull a background color in that case.
    2693           0 :       return mParent->FindOpaqueBackgroundColor(mClipRect);
    2694             :     }
    2695           0 :     return mParent->FindOpaqueBackgroundColorCoveringEverything();
    2696             :   }
    2697             :   // We are the root.
    2698         142 :   return mTree.UniformBackgroundColor();
    2699             : }
    2700             : 
    2701             : void
    2702        1123 : PaintedLayerData::UpdateCommonClipCount(
    2703             :     const DisplayItemClip& aCurrentClip)
    2704             : {
    2705        1123 :   if (mCommonClipCount >= 0) {
    2706        1067 :     mCommonClipCount = mItemClip.GetCommonRoundedRectCount(aCurrentClip, mCommonClipCount);
    2707             :   } else {
    2708             :     // first item in the layer
    2709          56 :     mCommonClipCount = aCurrentClip.GetRoundedRectCount();
    2710             :   }
    2711        1123 : }
    2712             : 
    2713             : bool
    2714         258 : PaintedLayerData::CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
    2715             : {
    2716         258 :   if (!mImage) {
    2717         201 :     return false;
    2718             :   }
    2719             : 
    2720          57 :   return mImage->CanOptimizeToImageLayer(mLayer->Manager(), aBuilder);
    2721             : }
    2722             : 
    2723             : already_AddRefed<ImageContainer>
    2724           0 : PaintedLayerData::GetContainerForImageLayer(nsDisplayListBuilder* aBuilder)
    2725             : {
    2726           0 :   if (!mImage) {
    2727           0 :     return nullptr;
    2728             :   }
    2729             : 
    2730           0 :   return mImage->GetContainer(mLayer->Manager(), aBuilder);
    2731             : }
    2732             : 
    2733         241 : PaintedLayerDataNode::PaintedLayerDataNode(PaintedLayerDataTree& aTree,
    2734             :                                            PaintedLayerDataNode* aParent,
    2735         241 :                                            AnimatedGeometryRoot* aAnimatedGeometryRoot)
    2736             :   : mTree(aTree)
    2737             :   , mParent(aParent)
    2738             :   , mAnimatedGeometryRoot(aAnimatedGeometryRoot)
    2739         241 :   , mAllDrawingAboveBackground(false)
    2740             : {
    2741         241 :   MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(mTree.Builder()->RootReferenceFrame(), *mAnimatedGeometryRoot));
    2742         241 :   mHasClip = mTree.IsClippedWithRespectToParentAnimatedGeometryRoot(mAnimatedGeometryRoot, &mClipRect);
    2743         241 : }
    2744             : 
    2745         482 : PaintedLayerDataNode::~PaintedLayerDataNode()
    2746             : {
    2747         241 :   MOZ_ASSERT(mPaintedLayerDataStack.IsEmpty());
    2748         241 :   MOZ_ASSERT(mChildren.IsEmpty());
    2749         241 : }
    2750             : 
    2751             : PaintedLayerDataNode*
    2752           2 : PaintedLayerDataNode::AddChildNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot)
    2753             : {
    2754           2 :   MOZ_ASSERT(aAnimatedGeometryRoot->mParentAGR == mAnimatedGeometryRoot);
    2755             :   UniquePtr<PaintedLayerDataNode> child =
    2756           4 :     MakeUnique<PaintedLayerDataNode>(mTree, this, aAnimatedGeometryRoot);
    2757           2 :   mChildren.AppendElement(Move(child));
    2758           4 :   return mChildren.LastElement().get();
    2759             : }
    2760             : 
    2761             : template<typename NewPaintedLayerCallbackType>
    2762             : PaintedLayerData*
    2763        1759 : PaintedLayerDataNode::FindPaintedLayerFor(const nsIntRect& aVisibleRect,
    2764             :                                           bool aBackfaceHidden,
    2765             :                                           const ActiveScrolledRoot* aASR,
    2766             :                                           const DisplayItemClipChain* aClipChain,
    2767             :                                           NewPaintedLayerCallbackType aNewPaintedLayerCallback)
    2768             : {
    2769        1759 :   if (!mPaintedLayerDataStack.IsEmpty()) {
    2770        1520 :     PaintedLayerData* lowestUsableLayer = nullptr;
    2771        1640 :     for (auto& data : Reversed(mPaintedLayerDataStack)) {
    2772        1537 :       if (data.mVisibleAboveRegion.Intersects(aVisibleRect)) {
    2773          19 :         break;
    2774             :       }
    2775        4554 :       if (data.mBackfaceHidden == aBackfaceHidden &&
    2776        3036 :           data.mASR == aASR &&
    2777        1518 :           DisplayItemClipChain::Equal(data.mClipChain, aClipChain)) {
    2778        1518 :         lowestUsableLayer = &data;
    2779             :       }
    2780             :       // Also check whether the event-regions intersect the visible rect,
    2781             :       // unless we're in an inactive layer, in which case the event-regions
    2782             :       // will be hoisted out into their own layer.
    2783             :       // For performance reasons, we check the intersection with the bounds
    2784             :       // of the event-regions.
    2785        4227 :       if (!mTree.ContState().IsInInactiveLayer() &&
    2786        1542 :           (data.mScaledHitRegionBounds.Intersects(aVisibleRect) ||
    2787         125 :            data.mScaledMaybeHitRegionBounds.Intersects(aVisibleRect))) {
    2788        1292 :         break;
    2789             :       }
    2790             :       // If the visible region intersects with the current layer then we
    2791             :       // can't possibly use any of the layers below it, so stop the search
    2792             :       // now.
    2793             :       //
    2794             :       // If we're trying to minimize painted layer size and we don't
    2795             :       // intersect the current visible region, then make sure we don't
    2796             :       // use this painted layer.
    2797         226 :       if (data.mVisibleRegion.Intersects(aVisibleRect)) {
    2798         106 :         break;
    2799         120 :       } else if (gfxPrefs::LayoutSmallerPaintedLayers()) {
    2800           0 :         lowestUsableLayer = nullptr;
    2801             :       }
    2802             :     }
    2803        1520 :     if (lowestUsableLayer) {
    2804        1501 :       return lowestUsableLayer;
    2805             :     }
    2806             :   }
    2807         258 :   return mPaintedLayerDataStack.AppendElement(aNewPaintedLayerCallback());
    2808             : }
    2809             : 
    2810             : void
    2811        1596 : PaintedLayerDataNode::FinishChildrenIntersecting(const nsIntRect& aRect)
    2812             : {
    2813        1596 :   for (int32_t i = mChildren.Length() - 1; i >= 0; i--) {
    2814           0 :     if (mChildren[i]->Intersects(aRect)) {
    2815           0 :       mChildren[i]->Finish(true);
    2816           0 :       mChildren.RemoveElementAt(i);
    2817             :     }
    2818             :   }
    2819        1596 : }
    2820             : 
    2821             : void
    2822         241 : PaintedLayerDataNode::FinishAllChildren(bool aThisNodeNeedsAccurateVisibleAboveRegion)
    2823             : {
    2824         243 :   for (int32_t i = mChildren.Length() - 1; i >= 0; i--) {
    2825           2 :     mChildren[i]->Finish(aThisNodeNeedsAccurateVisibleAboveRegion);
    2826             :   }
    2827         241 :   mChildren.Clear();
    2828         241 : }
    2829             : 
    2830             : void
    2831         241 : PaintedLayerDataNode::Finish(bool aParentNeedsAccurateVisibleAboveRegion)
    2832             : {
    2833             :   // Skip "visible above region" maintenance, because this node is going away.
    2834         241 :   FinishAllChildren(false);
    2835             : 
    2836         241 :   PopAllPaintedLayerData();
    2837             : 
    2838         241 :   if (mParent && aParentNeedsAccurateVisibleAboveRegion) {
    2839           0 :     if (mHasClip) {
    2840           0 :       mParent->AddToVisibleAboveRegion(mClipRect);
    2841             :     } else {
    2842           0 :       mParent->SetAllDrawingAbove();
    2843             :     }
    2844             :   }
    2845         241 :   mTree.NodeWasFinished(mAnimatedGeometryRoot);
    2846         241 : }
    2847             : 
    2848             : void
    2849          76 : PaintedLayerDataNode::AddToVisibleAboveRegion(const nsIntRect& aRect)
    2850             : {
    2851          76 :   nsIntRegion& visibleAboveRegion = mPaintedLayerDataStack.IsEmpty()
    2852             :     ? mVisibleAboveBackgroundRegion
    2853          76 :     : mPaintedLayerDataStack.LastElement().mVisibleAboveRegion;
    2854          76 :   visibleAboveRegion.Or(visibleAboveRegion, aRect);
    2855          76 :   visibleAboveRegion.SimplifyOutward(8);
    2856          76 : }
    2857             : 
    2858             : void
    2859           0 : PaintedLayerDataNode::SetAllDrawingAbove()
    2860             : {
    2861           0 :   PopAllPaintedLayerData();
    2862           0 :   mAllDrawingAboveBackground = true;
    2863           0 :   mVisibleAboveBackgroundRegion.SetEmpty();
    2864           0 : }
    2865             : 
    2866             : void
    2867         258 : PaintedLayerDataNode::PopPaintedLayerData()
    2868             : {
    2869         258 :   MOZ_ASSERT(!mPaintedLayerDataStack.IsEmpty());
    2870         258 :   size_t lastIndex = mPaintedLayerDataStack.Length() - 1;
    2871         258 :   PaintedLayerData& data = mPaintedLayerDataStack[lastIndex];
    2872         630 :   mTree.ContState().FinishPaintedLayerData(data, [this, &data, lastIndex]() {
    2873         248 :     return this->FindOpaqueBackgroundColor(data.mVisibleRegion, lastIndex);
    2874         640 :   });
    2875         258 :   mPaintedLayerDataStack.RemoveElementAt(lastIndex);
    2876         258 : }
    2877             : 
    2878             : void
    2879         499 : PaintedLayerDataNode::PopAllPaintedLayerData()
    2880             : {
    2881         757 :   while (!mPaintedLayerDataStack.IsEmpty()) {
    2882         258 :     PopPaintedLayerData();
    2883             :   }
    2884         241 : }
    2885             : 
    2886             : nsDisplayListBuilder*
    2887         484 : PaintedLayerDataTree::Builder() const
    2888             : {
    2889         484 :   return mContainerState.Builder();
    2890             : }
    2891             : 
    2892             : void
    2893         239 : PaintedLayerDataTree::Finish()
    2894             : {
    2895         239 :   if (mRoot) {
    2896         239 :     mRoot->Finish(false);
    2897             :   }
    2898         239 :   MOZ_ASSERT(mNodes.Count() == 0);
    2899         239 :   mRoot = nullptr;
    2900         239 : }
    2901             : 
    2902             : void
    2903         241 : PaintedLayerDataTree::NodeWasFinished(AnimatedGeometryRoot* aAnimatedGeometryRoot)
    2904             : {
    2905         241 :   mNodes.Remove(aAnimatedGeometryRoot);
    2906         241 : }
    2907             : 
    2908             : void
    2909          76 : PaintedLayerDataTree::AddingOwnLayer(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    2910             :                                      const nsIntRect* aRect,
    2911             :                                      nscolor* aOutUniformBackgroundColor)
    2912             : {
    2913          76 :   FinishPotentiallyIntersectingNodes(aAnimatedGeometryRoot, aRect);
    2914          76 :   PaintedLayerDataNode* node = EnsureNodeFor(aAnimatedGeometryRoot);
    2915          76 :   if (aRect) {
    2916          76 :     if (aOutUniformBackgroundColor) {
    2917          74 :       *aOutUniformBackgroundColor = node->FindOpaqueBackgroundColor(*aRect);
    2918             :     }
    2919          76 :     node->AddToVisibleAboveRegion(*aRect);
    2920             :   } else {
    2921           0 :     if (aOutUniformBackgroundColor) {
    2922           0 :       *aOutUniformBackgroundColor = node->FindOpaqueBackgroundColorCoveringEverything();
    2923             :     }
    2924           0 :     node->SetAllDrawingAbove();
    2925             :   }
    2926          76 : }
    2927             : 
    2928             : template<typename NewPaintedLayerCallbackType>
    2929             : PaintedLayerData*
    2930        1759 : PaintedLayerDataTree::FindPaintedLayerFor(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    2931             :                                           const ActiveScrolledRoot* aASR,
    2932             :                                           const DisplayItemClipChain* aClipChain,
    2933             :                                           const nsIntRect& aVisibleRect,
    2934             :                                           bool aBackfaceHidden,
    2935             :                                           NewPaintedLayerCallbackType aNewPaintedLayerCallback)
    2936             : {
    2937        1759 :   const nsIntRect* bounds = &aVisibleRect;
    2938        1759 :   FinishPotentiallyIntersectingNodes(aAnimatedGeometryRoot, bounds);
    2939        1759 :   PaintedLayerDataNode* node = EnsureNodeFor(aAnimatedGeometryRoot);
    2940             : 
    2941             :   PaintedLayerData* data =
    2942             :     node->FindPaintedLayerFor(aVisibleRect, aBackfaceHidden, aASR, aClipChain,
    2943        1759 :                               aNewPaintedLayerCallback);
    2944        1759 :   return data;
    2945             : }
    2946             : 
    2947             : void
    2948        1835 : PaintedLayerDataTree::FinishPotentiallyIntersectingNodes(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    2949             :                                                          const nsIntRect* aRect)
    2950             : {
    2951        1835 :   AnimatedGeometryRoot* ancestorThatIsChildOfCommonAncestor = nullptr;
    2952             :   PaintedLayerDataNode* ancestorNode =
    2953             :     FindNodeForAncestorAnimatedGeometryRoot(aAnimatedGeometryRoot,
    2954        1835 :                                             &ancestorThatIsChildOfCommonAncestor);
    2955        1835 :   if (!ancestorNode) {
    2956             :     // None of our ancestors are in the tree. This should only happen if this
    2957             :     // is the very first item we're looking at.
    2958         239 :     MOZ_ASSERT(!mRoot);
    2959        2072 :     return;
    2960             :   }
    2961             : 
    2962        1596 :   if (ancestorNode->GetAnimatedGeometryRoot() == aAnimatedGeometryRoot) {
    2963             :     // aAnimatedGeometryRoot already has a node in the tree.
    2964             :     // This is the common case.
    2965        1594 :     MOZ_ASSERT(!ancestorThatIsChildOfCommonAncestor);
    2966        1594 :     if (aRect) {
    2967        1594 :       ancestorNode->FinishChildrenIntersecting(*aRect);
    2968             :     } else {
    2969           0 :       ancestorNode->FinishAllChildren();
    2970             :     }
    2971        1594 :     return;
    2972             :   }
    2973             : 
    2974             :   // We have found an existing ancestor, but it's a proper ancestor of our
    2975             :   // animated geometry root.
    2976             :   // ancestorThatIsChildOfCommonAncestor is the last animated geometry root
    2977             :   // encountered on the way up from aAnimatedGeometryRoot to ancestorNode.
    2978           2 :   MOZ_ASSERT(ancestorThatIsChildOfCommonAncestor);
    2979           2 :   MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(*ancestorThatIsChildOfCommonAncestor, *aAnimatedGeometryRoot));
    2980           2 :   MOZ_ASSERT(ancestorThatIsChildOfCommonAncestor->mParentAGR == ancestorNode->GetAnimatedGeometryRoot());
    2981             : 
    2982             :   // ancestorThatIsChildOfCommonAncestor is not in the tree yet!
    2983           2 :   MOZ_ASSERT(!mNodes.Get(ancestorThatIsChildOfCommonAncestor));
    2984             : 
    2985             :   // We're about to add a node for ancestorThatIsChildOfCommonAncestor, so we
    2986             :   // finish all intersecting siblings.
    2987           2 :   nsIntRect clip;
    2988           2 :   if (IsClippedWithRespectToParentAnimatedGeometryRoot(ancestorThatIsChildOfCommonAncestor, &clip)) {
    2989           2 :     ancestorNode->FinishChildrenIntersecting(clip);
    2990             :   } else {
    2991           0 :     ancestorNode->FinishAllChildren();
    2992             :   }
    2993             : }
    2994             : 
    2995             : PaintedLayerDataNode*
    2996        1837 : PaintedLayerDataTree::EnsureNodeFor(AnimatedGeometryRoot* aAnimatedGeometryRoot)
    2997             : {
    2998        1837 :   MOZ_ASSERT(aAnimatedGeometryRoot);
    2999        1837 :   PaintedLayerDataNode* node = mNodes.Get(aAnimatedGeometryRoot);
    3000        1837 :   if (node) {
    3001        1596 :     return node;
    3002             :   }
    3003             : 
    3004         241 :   AnimatedGeometryRoot* parentAnimatedGeometryRoot = aAnimatedGeometryRoot->mParentAGR;
    3005         241 :   if (!parentAnimatedGeometryRoot) {
    3006         239 :     MOZ_ASSERT(!mRoot);
    3007         239 :     MOZ_ASSERT(*aAnimatedGeometryRoot == Builder()->RootReferenceFrame());
    3008         239 :     mRoot = MakeUnique<PaintedLayerDataNode>(*this, nullptr, aAnimatedGeometryRoot);
    3009         239 :     node = mRoot.get();
    3010             :   } else {
    3011           2 :     PaintedLayerDataNode* parentNode = EnsureNodeFor(parentAnimatedGeometryRoot);
    3012           2 :     MOZ_ASSERT(parentNode);
    3013           2 :     node = parentNode->AddChildNodeFor(aAnimatedGeometryRoot);
    3014             :   }
    3015         241 :   MOZ_ASSERT(node);
    3016         241 :   mNodes.Put(aAnimatedGeometryRoot, node);
    3017         241 :   return node;
    3018             : }
    3019             : 
    3020             : bool
    3021         243 : PaintedLayerDataTree::IsClippedWithRespectToParentAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    3022             :                                                                        nsIntRect* aOutClip)
    3023             : {
    3024         243 :   nsIScrollableFrame* scrollableFrame = nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
    3025         243 :   if (!scrollableFrame) {
    3026         239 :     return false;
    3027             :   }
    3028           4 :   nsIFrame* scrollFrame = do_QueryFrame(scrollableFrame);
    3029           8 :   nsRect scrollPort = scrollableFrame->GetScrollPortRect() + Builder()->ToReferenceFrame(scrollFrame);
    3030           4 :   *aOutClip = mContainerState.ScaleToNearestPixels(scrollPort);
    3031           4 :   return true;
    3032             : }
    3033             : 
    3034             : PaintedLayerDataNode*
    3035        2076 : PaintedLayerDataTree::FindNodeForAncestorAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot,
    3036             :                                                               AnimatedGeometryRoot** aOutAncestorChild)
    3037             : {
    3038        2076 :   if (!aAnimatedGeometryRoot) {
    3039         239 :     return nullptr;
    3040             :   }
    3041        1837 :   PaintedLayerDataNode* node = mNodes.Get(aAnimatedGeometryRoot);
    3042        1837 :   if (node) {
    3043        1596 :     return node;
    3044             :   }
    3045         241 :   *aOutAncestorChild = aAnimatedGeometryRoot;
    3046         241 :   return FindNodeForAncestorAnimatedGeometryRoot(aAnimatedGeometryRoot->mParentAGR, aOutAncestorChild);
    3047             : }
    3048             : 
    3049             : static bool
    3050          14 : CanOptimizeAwayPaintedLayer(PaintedLayerData* aData,
    3051             :                            FrameLayerBuilder* aLayerBuilder)
    3052             : {
    3053          14 :   if (!aLayerBuilder->IsBuildingRetainedLayers()) {
    3054           0 :     return false;
    3055             :   }
    3056             : 
    3057             :   // If there's no painted layer with valid content in it that we can reuse,
    3058             :   // always create a color or image layer (and potentially throw away an
    3059             :   // existing completely invalid painted layer).
    3060          14 :   if (aData->mLayer->GetValidRegion().IsEmpty()) {
    3061           3 :     return true;
    3062             :   }
    3063             : 
    3064             :   // There is an existing painted layer we can reuse. Throwing it away can make
    3065             :   // compositing cheaper (see bug 946952), but it might cause us to re-allocate
    3066             :   // the painted layer frequently due to an animation. So we only discard it if
    3067             :   // we're in tree compression mode, which is triggered at a low frequency.
    3068          11 :   return aLayerBuilder->CheckInLayerTreeCompressionMode();
    3069             : }
    3070             : 
    3071             : #ifdef DEBUG
    3072         337 : static int32_t FindIndexOfLayerIn(nsTArray<NewLayerEntry>& aArray,
    3073             :                                   Layer* aLayer)
    3074             : {
    3075        1180 :   for (uint32_t i = 0; i < aArray.Length(); ++i) {
    3076         843 :     if (aArray[i].mLayer == aLayer) {
    3077           0 :       return i;
    3078             :     }
    3079             :   }
    3080         337 :   return -1;
    3081             : }
    3082             : #endif
    3083             : 
    3084             : already_AddRefed<Layer>
    3085           0 : ContainerState::PrepareImageLayer(PaintedLayerData* aData)
    3086             : {
    3087             :   RefPtr<ImageContainer> imageContainer =
    3088           0 :     aData->GetContainerForImageLayer(mBuilder);
    3089           0 :   if (!imageContainer) {
    3090           0 :     return nullptr;
    3091             :   }
    3092             : 
    3093           0 :   RefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(aData->mLayer);
    3094           0 :   imageLayer->SetContainer(imageContainer);
    3095           0 :   aData->mImage->ConfigureLayer(imageLayer, mParameters);
    3096           0 :   imageLayer->SetPostScale(mParameters.mXScale,
    3097           0 :                            mParameters.mYScale);
    3098             : 
    3099           0 :   if (aData->mItemClip.HasClip()) {
    3100             :     ParentLayerIntRect clip =
    3101           0 :       ViewAs<ParentLayerPixel>(ScaleToNearestPixels(aData->mItemClip.GetClipRect()));
    3102           0 :     clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
    3103           0 :     imageLayer->SetClipRect(Some(clip));
    3104             :   } else {
    3105           0 :     imageLayer->SetClipRect(Nothing());
    3106             :   }
    3107             : 
    3108           0 :   FLB_LOG_PAINTED_LAYER_DECISION(aData,
    3109             :                                  "  Selected image layer=%p\n", imageLayer.get());
    3110             : 
    3111           0 :   return imageLayer.forget();
    3112             : }
    3113             : 
    3114             : already_AddRefed<Layer>
    3115           3 : ContainerState::PrepareColorLayer(PaintedLayerData* aData)
    3116             : {
    3117           6 :   RefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(aData->mLayer);
    3118           3 :   colorLayer->SetColor(Color::FromABGR(aData->mSolidColor));
    3119             : 
    3120             :   // Copy transform
    3121           3 :   colorLayer->SetBaseTransform(aData->mLayer->GetBaseTransform());
    3122           6 :   colorLayer->SetPostScale(aData->mLayer->GetPostXScale(),
    3123           9 :                            aData->mLayer->GetPostYScale());
    3124             : 
    3125           3 :   nsIntRect visibleRect = aData->mVisibleRegion.GetBounds();
    3126           3 :   visibleRect.MoveBy(-GetTranslationForPaintedLayer(aData->mLayer));
    3127           3 :   colorLayer->SetBounds(visibleRect);
    3128           3 :   colorLayer->SetClipRect(Nothing());
    3129             : 
    3130           3 :   FLB_LOG_PAINTED_LAYER_DECISION(aData,
    3131             :                                  "  Selected color layer=%p\n", colorLayer.get());
    3132             : 
    3133           6 :   return colorLayer.forget();
    3134             : }
    3135             : 
    3136             : static void
    3137         261 : SetBackfaceHiddenForLayer(bool aBackfaceHidden, Layer* aLayer)
    3138             : {
    3139         261 :   if (aBackfaceHidden) {
    3140           0 :     aLayer->SetContentFlags(aLayer->GetContentFlags() |
    3141           0 :                             Layer::CONTENT_BACKFACE_HIDDEN);
    3142             :   } else {
    3143         261 :     aLayer->SetContentFlags(aLayer->GetContentFlags() &
    3144         261 :                             ~Layer::CONTENT_BACKFACE_HIDDEN);
    3145             :   }
    3146         261 : }
    3147             : 
    3148             : template<typename FindOpaqueBackgroundColorCallbackType>
    3149         258 : void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor)
    3150             : {
    3151         258 :   PaintedLayerData* data = &aData;
    3152             : 
    3153         258 :   if (!data->mLayer) {
    3154             :     // No layer was recycled, so we create a new one.
    3155         290 :     RefPtr<PaintedLayer> paintedLayer = CreatePaintedLayer(data);
    3156         145 :     data->mLayer = paintedLayer;
    3157             : 
    3158         145 :     NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, paintedLayer) < 0,
    3159             :                  "Layer already in list???");
    3160         145 :     mNewChildLayers[data->mNewChildLayersIndex].mLayer = paintedLayer.forget();
    3161             :   }
    3162             : 
    3163        1556 :   for (auto& item : data->mAssignedDisplayItems) {
    3164        1298 :     MOZ_ASSERT(item.mItem->GetType() != nsDisplayItem::TYPE_LAYER_EVENT_REGIONS);
    3165             : 
    3166        1298 :     InvalidateForLayerChange(item.mItem, data->mLayer);
    3167        1298 :     mLayerBuilder->AddPaintedDisplayItem(data, item.mItem, item.mClip,
    3168             :                                          *this, item.mLayerState,
    3169             :                                          data->mAnimatedGeometryRootOffset);
    3170             :   }
    3171             : 
    3172         258 :   NewLayerEntry* newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex];
    3173             : 
    3174         516 :   RefPtr<Layer> layer;
    3175         258 :   bool canOptimizeToImageLayer = data->CanOptimizeToImageLayer(mBuilder);
    3176             : 
    3177         258 :   FLB_LOG_PAINTED_LAYER_DECISION(data, "Selecting layer for pld=%p\n", data);
    3178         258 :   FLB_LOG_PAINTED_LAYER_DECISION(data, "  Solid=%i, hasImage=%c, canOptimizeAwayPaintedLayer=%i\n",
    3179             :           data->mIsSolidColorInVisibleRegion, canOptimizeToImageLayer ? 'y' : 'n',
    3180             :           CanOptimizeAwayPaintedLayer(data, mLayerBuilder));
    3181             : 
    3182         272 :   if ((data->mIsSolidColorInVisibleRegion || canOptimizeToImageLayer) &&
    3183          14 :       CanOptimizeAwayPaintedLayer(data, mLayerBuilder)) {
    3184           3 :     NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && canOptimizeToImageLayer),
    3185             :                  "Can't be a solid color as well as an image!");
    3186             : 
    3187           3 :     layer = canOptimizeToImageLayer ? PrepareImageLayer(data)
    3188             :                                     : PrepareColorLayer(data);
    3189             : 
    3190           3 :     if (layer) {
    3191           3 :       NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
    3192             :                    "Layer already in list???");
    3193           3 :       NS_ASSERTION(newLayerEntry->mLayer == data->mLayer,
    3194             :                    "Painted layer at wrong index");
    3195             :       // Store optimized layer in reserved slot
    3196           3 :       NewLayerEntry* paintedLayerEntry = newLayerEntry;
    3197           3 :       newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1];
    3198           3 :       NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?");
    3199           3 :       newLayerEntry->mLayer = layer;
    3200           3 :       newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot;
    3201           3 :       newLayerEntry->mASR = paintedLayerEntry->mASR;
    3202           3 :       newLayerEntry->mClipChain = paintedLayerEntry->mClipChain;
    3203           3 :       newLayerEntry->mScrollMetadataASR = paintedLayerEntry->mScrollMetadataASR;
    3204             : 
    3205             :       // Hide the PaintedLayer. We leave it in the layer tree so that we
    3206             :       // can find and recycle it later.
    3207           3 :       ParentLayerIntRect emptyRect;
    3208           3 :       data->mLayer->SetClipRect(Some(emptyRect));
    3209           3 :       data->mLayer->SetVisibleRegion(LayerIntRegion());
    3210           3 :       data->mLayer->InvalidateWholeLayer();
    3211           3 :       data->mLayer->SetEventRegions(EventRegions());
    3212             : 
    3213           6 :       for (auto& item : data->mAssignedDisplayItems) {
    3214           3 :         mLayerBuilder->StoreOptimizedLayerForFrame(item.mItem, layer);
    3215             :       }
    3216             :     }
    3217             :   }
    3218             : 
    3219         258 :   if (!layer) {
    3220             :     // We couldn't optimize to an image layer or a color layer above.
    3221         255 :     layer = data->mLayer;
    3222         255 :     layer->SetClipRect(Nothing());
    3223         255 :     FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected painted layer=%p\n", layer.get());
    3224             :   }
    3225             : 
    3226         258 :   if (mLayerBuilder->IsBuildingRetainedLayers()) {
    3227          73 :     newLayerEntry->mVisibleRegion = data->mVisibleRegion;
    3228          73 :     newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
    3229          73 :     newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
    3230          73 :     newLayerEntry->mOpaqueForAnimatedGeometryRootParent = data->mOpaqueForAnimatedGeometryRootParent;
    3231             :   } else {
    3232         185 :     SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion);
    3233             :   }
    3234             : 
    3235             : #ifdef MOZ_DUMP_PAINTING
    3236         258 :   if (!data->mLog.IsEmpty()) {
    3237           0 :     if (PaintedLayerData* containingPld = mLayerBuilder->GetContainingPaintedLayerData()) {
    3238           0 :       containingPld->mLayer->AddExtraDumpInfo(nsCString(data->mLog));
    3239             :     } else {
    3240           0 :       layer->AddExtraDumpInfo(nsCString(data->mLog));
    3241             :     }
    3242             :   }
    3243             : #endif
    3244             : 
    3245         516 :   nsIntRegion transparentRegion;
    3246         258 :   transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion);
    3247         258 :   bool isOpaque = transparentRegion.IsEmpty();
    3248             :   // For translucent PaintedLayers, try to find an opaque background
    3249             :   // color that covers the entire area beneath it so we can pull that
    3250             :   // color into this layer to make it opaque.
    3251         258 :   if (layer == data->mLayer) {
    3252         255 :     nscolor backgroundColor = NS_RGBA(0,0,0,0);
    3253         255 :     if (!isOpaque) {
    3254         124 :       backgroundColor = aFindOpaqueBackgroundColor();
    3255         124 :       if (NS_GET_A(backgroundColor) == 255) {
    3256           0 :         isOpaque = true;
    3257             :       }
    3258             :     }
    3259             : 
    3260             :     // Store the background color
    3261             :     PaintedDisplayItemLayerUserData* userData =
    3262         255 :       GetPaintedDisplayItemLayerUserData(data->mLayer);
    3263         255 :     NS_ASSERTION(userData, "where did our user data go?");
    3264         255 :     if (userData->mForcedBackgroundColor != backgroundColor) {
    3265             :       // Invalidate the entire target PaintedLayer since we're changing
    3266             :       // the background color
    3267             : #ifdef MOZ_DUMP_PAINTING
    3268           0 :       if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    3269           0 :         printf_stderr("Forced background color has changed from #%08X to #%08X on layer %p\n",
    3270             :                       userData->mForcedBackgroundColor, backgroundColor, data->mLayer);
    3271           0 :         nsAutoCString str;
    3272           0 :         AppendToString(str, data->mLayer->GetValidRegion());
    3273           0 :         printf_stderr("Invalidating layer %p: %s\n", data->mLayer, str.get());
    3274             :       }
    3275             : #endif
    3276           0 :       data->mLayer->InvalidateWholeLayer();
    3277             :     }
    3278         255 :     userData->mForcedBackgroundColor = backgroundColor;
    3279             : 
    3280         255 :     userData->mFontSmoothingBackgroundColor = data->mFontSmoothingBackgroundColor;
    3281             : 
    3282             :     // use a mask layer for rounded rect clipping.
    3283             :     // data->mCommonClipCount may be -1 if we haven't put any actual
    3284             :     // drawable items in this layer (i.e. it's only catching events).
    3285             :     int32_t commonClipCount;
    3286         255 :     commonClipCount = std::max(0, data->mCommonClipCount);
    3287         255 :     SetupMaskLayer(layer, data->mItemClip, commonClipCount);
    3288             :     // copy commonClipCount to the entry
    3289         255 :     FrameLayerBuilder::PaintedLayerItemsEntry* entry = mLayerBuilder->
    3290         510 :       GetPaintedLayerItemsEntry(static_cast<PaintedLayer*>(layer.get()));
    3291         255 :     entry->mCommonClipCount = commonClipCount;
    3292             :   } else {
    3293             :     // mask layer for image and color layers
    3294           3 :     SetupMaskLayer(layer, data->mItemClip);
    3295             :   }
    3296             : 
    3297         258 :   uint32_t flags = 0;
    3298         258 :   nsIWidget* widget = mContainerReferenceFrame->PresContext()->GetRootWidget();
    3299             :   // See bug 941095. Not quite ready to disable this.
    3300         258 :   bool hidpi = false && widget && widget->GetDefaultScale().scale >= 2;
    3301         258 :   if (hidpi) {
    3302           0 :     flags |= Layer::CONTENT_DISABLE_SUBPIXEL_AA;
    3303             :   }
    3304         258 :   if (isOpaque && !data->mForceTransparentSurface) {
    3305         134 :     flags |= Layer::CONTENT_OPAQUE;
    3306         124 :   } else if (data->mNeedComponentAlpha && !hidpi) {
    3307           5 :     flags |= Layer::CONTENT_COMPONENT_ALPHA;
    3308             :   }
    3309         258 :   if (data->mDisableFlattening) {
    3310           0 :     flags |= Layer::CONTENT_DISABLE_FLATTENING;
    3311             :   }
    3312         258 :   layer->SetContentFlags(flags);
    3313             : 
    3314             :   PaintedLayerData* containingPaintedLayerData =
    3315         258 :      mLayerBuilder->GetContainingPaintedLayerData();
    3316             :   // If we're building layers for an inactive layer, the event regions are
    3317             :   // clipped to the inactive layer's clip prior to being combined into the
    3318             :   // event regions of the containing PLD.
    3319             :   // For the dispatch-to-content and maybe-hit regions, rounded corners on
    3320             :   // the clip are ignored, since these are approximate regions. For the
    3321             :   // remaining regions, rounded corners in the clip cause the region to
    3322             :   // be combined into the corresponding "imprecise" region of the
    3323             :   // containing's PLD (e.g. the maybe-hit region instead of the hit region).
    3324         258 :   const DisplayItemClip* inactiveLayerClip = mLayerBuilder->GetInactiveLayerClip();
    3325         258 :   if (containingPaintedLayerData) {
    3326         143 :     if (!data->mDispatchToContentHitRegion.GetBounds().IsEmpty()) {
    3327             :       nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
    3328             :         mContainerReferenceFrame,
    3329             :         data->mDispatchToContentHitRegion.GetBounds(),
    3330           0 :         containingPaintedLayerData->mReferenceFrame);
    3331           0 :       if (inactiveLayerClip) {
    3332           0 :         rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
    3333             :       }
    3334           0 :       containingPaintedLayerData->mDispatchToContentHitRegion.Or(
    3335             :         containingPaintedLayerData->mDispatchToContentHitRegion, rect);
    3336             :     }
    3337         143 :     if (!data->mMaybeHitRegion.GetBounds().IsEmpty()) {
    3338             :       nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
    3339             :         mContainerReferenceFrame,
    3340             :         data->mMaybeHitRegion.GetBounds(),
    3341         102 :         containingPaintedLayerData->mReferenceFrame);
    3342          51 :       if (inactiveLayerClip) {
    3343          51 :         rect = inactiveLayerClip->ApplyNonRoundedIntersection(rect);
    3344             :       }
    3345          51 :       containingPaintedLayerData->mMaybeHitRegion.Or(
    3346             :         containingPaintedLayerData->mMaybeHitRegion, rect);
    3347          51 :       containingPaintedLayerData->mMaybeHitRegion.SimplifyOutward(8);
    3348             :     }
    3349         286 :     Maybe<Matrix4x4> matrixCache;
    3350         143 :     nsLayoutUtils::TransformToAncestorAndCombineRegions(
    3351             :       data->mHitRegion,
    3352             :       mContainerReferenceFrame,
    3353             :       containingPaintedLayerData->mReferenceFrame,
    3354             :       &containingPaintedLayerData->mHitRegion,
    3355             :       &containingPaintedLayerData->mMaybeHitRegion,
    3356             :       &matrixCache,
    3357             :       inactiveLayerClip);
    3358             :     // See the comment in nsDisplayList::AddFrame, where the touch action regions
    3359             :     // are handled. The same thing applies here.
    3360             :     bool alreadyHadRegions =
    3361         286 :         !containingPaintedLayerData->mNoActionRegion.IsEmpty() ||
    3362         286 :         !containingPaintedLayerData->mHorizontalPanRegion.IsEmpty() ||
    3363         286 :         !containingPaintedLayerData->mVerticalPanRegion.IsEmpty();
    3364         143 :     nsLayoutUtils::TransformToAncestorAndCombineRegions(
    3365             :       data->mNoActionRegion,
    3366             :       mContainerReferenceFrame,
    3367             :       containingPaintedLayerData->mReferenceFrame,
    3368             :       &containingPaintedLayerData->mNoActionRegion,
    3369             :       &containingPaintedLayerData->mDispatchToContentHitRegion,
    3370             :       &matrixCache,
    3371             :       inactiveLayerClip);
    3372         143 :     nsLayoutUtils::TransformToAncestorAndCombineRegions(
    3373             :       data->mHorizontalPanRegion,
    3374             :       mContainerReferenceFrame,
    3375             :       containingPaintedLayerData->mReferenceFrame,
    3376             :       &containingPaintedLayerData->mHorizontalPanRegion,
    3377             :       &containingPaintedLayerData->mDispatchToContentHitRegion,
    3378             :       &matrixCache,
    3379             :       inactiveLayerClip);
    3380         143 :     nsLayoutUtils::TransformToAncestorAndCombineRegions(
    3381             :       data->mVerticalPanRegion,
    3382             :       mContainerReferenceFrame,
    3383             :       containingPaintedLayerData->mReferenceFrame,
    3384             :       &containingPaintedLayerData->mVerticalPanRegion,
    3385             :       &containingPaintedLayerData->mDispatchToContentHitRegion,
    3386             :       &matrixCache,
    3387             :       inactiveLayerClip);
    3388         143 :     if (alreadyHadRegions) {
    3389           0 :       containingPaintedLayerData->mDispatchToContentHitRegion.OrWith(
    3390             :         containingPaintedLayerData->CombinedTouchActionRegion());
    3391             :     }
    3392             :   } else {
    3393         230 :     EventRegions regions;
    3394         115 :     regions.mHitRegion = ScaleRegionToOutsidePixels(data->mHitRegion);
    3395         115 :     regions.mNoActionRegion = ScaleRegionToOutsidePixels(data->mNoActionRegion);
    3396         115 :     regions.mHorizontalPanRegion = ScaleRegionToOutsidePixels(data->mHorizontalPanRegion);
    3397         115 :     regions.mVerticalPanRegion = ScaleRegionToOutsidePixels(data->mVerticalPanRegion);
    3398             :     // Points whose hit-region status we're not sure about need to be dispatched
    3399             :     // to the content thread. If a point is in both maybeHitRegion and hitRegion
    3400             :     // then it's not a "maybe" any more, and doesn't go into the dispatch-to-
    3401             :     // content region.
    3402         230 :     nsIntRegion maybeHitRegion = ScaleRegionToOutsidePixels(data->mMaybeHitRegion);
    3403         115 :     regions.mDispatchToContentHitRegion.Sub(maybeHitRegion, regions.mHitRegion);
    3404         115 :     regions.mDispatchToContentHitRegion.OrWith(
    3405             :         ScaleRegionToOutsidePixels(data->mDispatchToContentHitRegion));
    3406         115 :     regions.mHitRegion.OrWith(maybeHitRegion);
    3407             : 
    3408         115 :     Matrix mat = layer->GetTransform().As2D();
    3409         115 :     mat.Invert();
    3410         115 :     regions.ApplyTranslationAndScale(mat._31, mat._32, mat._11, mat._22);
    3411             : 
    3412         115 :     layer->SetEventRegions(regions);
    3413             :   }
    3414             : 
    3415         258 :   SetBackfaceHiddenForLayer(data->mBackfaceHidden, data->mLayer);
    3416         258 :   if (layer != data->mLayer) {
    3417           3 :     SetBackfaceHiddenForLayer(data->mBackfaceHidden, layer);
    3418             :   }
    3419         258 : }
    3420             : 
    3421             : static bool
    3422           5 : IsItemAreaInWindowOpaqueRegion(nsDisplayListBuilder* aBuilder,
    3423             :                                nsDisplayItem* aItem,
    3424             :                                const nsRect& aComponentAlphaBounds)
    3425             : {
    3426           5 :   if (!aItem->Frame()->PresContext()->IsChrome()) {
    3427             :     // Assume that Web content is always in the window opaque region.
    3428           0 :     return true;
    3429             :   }
    3430           5 :   if (aItem->ReferenceFrame() != aBuilder->RootReferenceFrame()) {
    3431             :     // aItem is probably in some transformed subtree.
    3432             :     // We're not going to bother figuring out where this landed, we're just
    3433             :     // going to assume it might have landed over a transparent part of
    3434             :     // the window.
    3435           0 :     return false;
    3436             :   }
    3437           5 :   return aBuilder->GetWindowOpaqueRegion().Contains(aComponentAlphaBounds);
    3438             : }
    3439             : 
    3440             : void
    3441        1298 : PaintedLayerData::Accumulate(ContainerState* aState,
    3442             :                             nsDisplayItem* aItem,
    3443             :                             const nsIntRegion& aClippedOpaqueRegion,
    3444             :                             const nsIntRect& aVisibleRect,
    3445             :                             const DisplayItemClip& aClip,
    3446             :                             LayerState aLayerState)
    3447             : {
    3448        1298 :   FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating dp=%s(%p), f=%p against pld=%p\n", aItem->Name(), aItem, aItem->Frame(), this);
    3449             : 
    3450        1298 :   if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
    3451           0 :     mForceTransparentSurface = true;
    3452             :   }
    3453        1298 :   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
    3454             :     // Disable component alpha.
    3455             :     // Note that the transform (if any) on the PaintedLayer is always an integer translation so
    3456             :     // we don't have to factor that in here.
    3457           0 :     aItem->DisableComponentAlpha();
    3458             :   }
    3459             : 
    3460        1298 :   bool clipMatches = mItemClip == aClip;
    3461        1298 :   mItemClip = aClip;
    3462             : 
    3463        1298 :   mAssignedDisplayItems.AppendElement(AssignedDisplayItem(aItem, aClip, aLayerState));
    3464             : 
    3465        4804 :   if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aVisibleRect) &&
    3466        3242 :       mVisibleRegion.Contains(aVisibleRect) && !mImage) {
    3467             :     // A very common case! Most pages have a PaintedLayer with the page
    3468             :     // background (opaque) visible and most or all of the page content over the
    3469             :     // top of that background.
    3470             :     // The rest of this method won't do anything. mVisibleRegion and mOpaqueRegion
    3471             :     // don't need updating. mVisibleRegion contains aVisibleRect already,
    3472             :     // mOpaqueRegion contains aVisibleRect and therefore whatever the opaque
    3473             :     // region of the item is. mVisibleRegion must contain mOpaqueRegion
    3474             :     // and therefore aVisibleRect.
    3475         972 :     return;
    3476             :   }
    3477             : 
    3478             :   /* Mark as available for conversion to image layer if this is a nsDisplayImage and
    3479             :    * it's the only thing visible in this layer.
    3480             :    */
    3481        1222 :   if (nsIntRegion(aVisibleRect).Contains(mVisibleRegion) &&
    3482        1174 :       aClippedOpaqueRegion.Contains(mVisibleRegion) &&
    3483         196 :       aItem->SupportsOptimizingToImage()) {
    3484          57 :     mImage = static_cast<nsDisplayImageContainer*>(aItem);
    3485          57 :     FLB_LOG_PAINTED_LAYER_DECISION(this, "  Tracking image: nsDisplayImageContainer covers the layer\n");
    3486         269 :   } else if (mImage) {
    3487           0 :     FLB_LOG_PAINTED_LAYER_DECISION(this, "  No longer tracking image\n");
    3488           0 :     mImage = nullptr;
    3489             :   }
    3490             : 
    3491         326 :   bool isFirstVisibleItem = mVisibleRegion.IsEmpty();
    3492         326 :   if (isFirstVisibleItem) {
    3493             :     nscolor fontSmoothingBGColor;
    3494         172 :     if (aItem->ProvidesFontSmoothingBackgroundColor(&fontSmoothingBGColor)) {
    3495           0 :       mFontSmoothingBackgroundColor = fontSmoothingBGColor;
    3496             :     }
    3497             :   }
    3498             : 
    3499         652 :   Maybe<nscolor> uniformColor = aItem->IsUniform(aState->mBuilder);
    3500             : 
    3501             :   // Some display items have to exist (so they can set forceTransparentSurface
    3502             :   // below) but don't draw anything. They'll return true for isUniform but
    3503             :   // a color with opacity 0.
    3504         326 :   if (!uniformColor || NS_GET_A(*uniformColor) > 0) {
    3505             :     // Make sure that the visible area is covered by uniform pixels. In
    3506             :     // particular this excludes cases where the edges of the item are not
    3507             :     // pixel-aligned (thus the item will not be truly uniform).
    3508         308 :     if (uniformColor) {
    3509             :       bool snap;
    3510         130 :       nsRect bounds = aItem->GetBounds(aState->mBuilder, &snap);
    3511          65 :       if (!aState->ScaleToInsidePixels(bounds, snap).Contains(aVisibleRect)) {
    3512           0 :         uniformColor = Nothing();
    3513           0 :         FLB_LOG_PAINTED_LAYER_DECISION(this, "  Display item does not cover the visible rect\n");
    3514             :       }
    3515             :     }
    3516         308 :     if (uniformColor) {
    3517          65 :       if (isFirstVisibleItem) {
    3518             :         // This color is all we have
    3519          65 :         mSolidColor = *uniformColor;
    3520          65 :         mIsSolidColorInVisibleRegion = true;
    3521           0 :       } else if (mIsSolidColorInVisibleRegion &&
    3522           0 :                  mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect)) &&
    3523             :                  clipMatches) {
    3524             :         // we can just blend the colors together
    3525           0 :         mSolidColor = NS_ComposeColors(mSolidColor, *uniformColor);
    3526             :       } else {
    3527           0 :         FLB_LOG_PAINTED_LAYER_DECISION(this, "  Layer not a solid color: Can't blend colors togethers\n");
    3528           0 :         mIsSolidColorInVisibleRegion = false;
    3529             :       }
    3530             :     } else {
    3531         243 :       FLB_LOG_PAINTED_LAYER_DECISION(this, "  Layer is not a solid color: Display item is not uniform over the visible bound\n");
    3532         243 :       mIsSolidColorInVisibleRegion = false;
    3533             :     }
    3534             : 
    3535         308 :     mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
    3536         308 :     mVisibleRegion.SimplifyOutward(4);
    3537             :   }
    3538             : 
    3539         326 :   if (!aClippedOpaqueRegion.IsEmpty()) {
    3540         130 :     for (auto iter = aClippedOpaqueRegion.RectIter(); !iter.Done(); iter.Next()) {
    3541             :       // We don't use SimplifyInward here since it's not defined exactly
    3542             :       // what it will discard. For our purposes the most important case
    3543             :       // is a large opaque background at the bottom of z-order (e.g.,
    3544             :       // a canvas background), so we need to make sure that the first rect
    3545             :       // we see doesn't get discarded.
    3546         130 :       nsIntRegion tmp;
    3547          65 :       tmp.Or(mOpaqueRegion, iter.Get());
    3548             :        // Opaque display items in chrome documents whose window is partially
    3549             :        // transparent are always added to the opaque region. This helps ensure
    3550             :        // that we get as much subpixel-AA as possible in the chrome.
    3551          65 :        if (tmp.GetNumRects() <= 4 || aItem->Frame()->PresContext()->IsChrome()) {
    3552          65 :         mOpaqueRegion = Move(tmp);
    3553             :       }
    3554             :     }
    3555             :   }
    3556             : 
    3557         326 :   if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
    3558         652 :     nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder);
    3559         326 :     if (!componentAlpha.IsEmpty()) {
    3560             :       nsIntRect componentAlphaRect =
    3561          17 :         aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect);
    3562          17 :       if (!mOpaqueRegion.Contains(componentAlphaRect)) {
    3563          10 :         if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem,
    3564          10 :               componentAlpha.Intersect(aItem->GetVisibleRect()))) {
    3565           5 :           mNeedComponentAlpha = true;
    3566             :         } else {
    3567           0 :           aItem->DisableComponentAlpha();
    3568             :         }
    3569             :       }
    3570             :     }
    3571             :   }
    3572             : 
    3573             :   // Ensure animated text does not get flattened, even if it forces other
    3574             :   // content in the container to be layerized. The content backend might
    3575             :   // not support subpixel positioning of text that animated transforms can
    3576             :   // generate. bug 633097
    3577         978 :   if (aState->mParameters.mInActiveTransformedSubtree &&
    3578           0 :        (mNeedComponentAlpha ||
    3579         326 :          !aItem->GetComponentAlphaBounds(aState->mBuilder).IsEmpty())) {
    3580           0 :     mDisableFlattening = true;
    3581             :   }
    3582             : }
    3583             : 
    3584             : nsRegion
    3585           0 : PaintedLayerData::CombinedTouchActionRegion()
    3586             : {
    3587           0 :   nsRegion result;
    3588           0 :   result.Or(mHorizontalPanRegion, mVerticalPanRegion);
    3589           0 :   result.OrWith(mNoActionRegion);
    3590           0 :   return result;
    3591             : }
    3592             : 
    3593             : void
    3594         461 : PaintedLayerData::AccumulateEventRegions(ContainerState* aState, nsDisplayLayerEventRegions* aEventRegions)
    3595             : {
    3596         461 :   FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating event regions %p against pld=%p\n", aEventRegions, this);
    3597             : 
    3598         461 :   mHitRegion.OrWith(aEventRegions->HitRegion());
    3599         461 :   mMaybeHitRegion.OrWith(aEventRegions->MaybeHitRegion());
    3600         461 :   mDispatchToContentHitRegion.OrWith(aEventRegions->DispatchToContentHitRegion());
    3601             : 
    3602             :   // See the comment in nsDisplayList::AddFrame, where the touch action regions
    3603             :   // are handled. The same thing applies here.
    3604         922 :   bool alreadyHadRegions = !mNoActionRegion.IsEmpty() ||
    3605         922 :       !mHorizontalPanRegion.IsEmpty() ||
    3606         922 :       !mVerticalPanRegion.IsEmpty();
    3607         461 :   mNoActionRegion.OrWith(aEventRegions->NoActionRegion());
    3608         461 :   mHorizontalPanRegion.OrWith(aEventRegions->HorizontalPanRegion());
    3609         461 :   mVerticalPanRegion.OrWith(aEventRegions->VerticalPanRegion());
    3610         461 :   if (alreadyHadRegions) {
    3611           0 :     mDispatchToContentHitRegion.OrWith(CombinedTouchActionRegion());
    3612             :   }
    3613             : 
    3614             :   // Avoid quadratic performance as a result of the region growing to include
    3615             :   // and arbitrarily large number of rects, which can happen on some pages.
    3616         461 :   mMaybeHitRegion.SimplifyOutward(8);
    3617             : 
    3618             :   // Calculate scaled versions of the bounds of mHitRegion and mMaybeHitRegion
    3619             :   // for quick access in FindPaintedLayerFor().
    3620         461 :   mScaledHitRegionBounds = aState->ScaleToOutsidePixels(mHitRegion.GetBounds());
    3621         461 :   mScaledMaybeHitRegionBounds = aState->ScaleToOutsidePixels(mMaybeHitRegion.GetBounds());
    3622         461 : }
    3623             : 
    3624             : PaintedLayerData
    3625         258 : ContainerState::NewPaintedLayerData(nsDisplayItem* aItem,
    3626             :                                     AnimatedGeometryRoot* aAnimatedGeometryRoot,
    3627             :                                     const ActiveScrolledRoot* aASR,
    3628             :                                     const DisplayItemClipChain* aClipChain,
    3629             :                                     const ActiveScrolledRoot* aScrollMetadataASR,
    3630             :                                     const nsPoint& aTopLeft)
    3631             : {
    3632         258 :   PaintedLayerData data;
    3633         258 :   data.mAnimatedGeometryRoot = aAnimatedGeometryRoot;
    3634         258 :   data.mASR = aASR;
    3635         258 :   data.mClipChain = aClipChain;
    3636         258 :   data.mAnimatedGeometryRootOffset = aTopLeft;
    3637         258 :   data.mReferenceFrame = aItem->ReferenceFrame();
    3638         258 :   data.mBackfaceHidden = aItem->Frame()->In3DContextAndBackfaceIsHidden();
    3639             : 
    3640         258 :   data.mNewChildLayersIndex = mNewChildLayers.Length();
    3641         258 :   NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
    3642         258 :   newLayerEntry->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
    3643         258 :   newLayerEntry->mASR = aASR;
    3644         258 :   newLayerEntry->mScrollMetadataASR = aScrollMetadataASR;
    3645         258 :   newLayerEntry->mClipChain = aClipChain;
    3646             :   // newLayerEntry->mOpaqueRegion is filled in later from
    3647             :   // paintedLayerData->mOpaqueRegion, if necessary.
    3648             : 
    3649             :   // Allocate another entry for this layer's optimization to ColorLayer/ImageLayer
    3650         258 :   mNewChildLayers.AppendElement();
    3651             : 
    3652         258 :   return data;
    3653             : }
    3654             : 
    3655             : #ifdef MOZ_DUMP_PAINTING
    3656             : static void
    3657           0 : DumpPaintedImage(nsDisplayItem* aItem, SourceSurface* aSurface)
    3658             : {
    3659           0 :   nsCString string(aItem->Name());
    3660           0 :   string.Append('-');
    3661           0 :   string.AppendInt((uint64_t)aItem);
    3662           0 :   fprintf_stderr(gfxUtils::sDumpPaintFile, "<script>array[\"%s\"]=\"", string.BeginReading());
    3663           0 :   gfxUtils::DumpAsDataURI(aSurface, gfxUtils::sDumpPaintFile);
    3664           0 :   fprintf_stderr(gfxUtils::sDumpPaintFile, "\";</script>\n");
    3665           0 : }
    3666             : #endif
    3667             : 
    3668             : static void
    3669          30 : PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
    3670             :                    LayerManager* aManager,
    3671             :                    nsDisplayItem* aItem,
    3672             :                    gfxContext* aContext,
    3673             :                    gfxContext* aCtx)
    3674             : {
    3675             :   // This item has an inactive layer. Render it to a PaintedLayer
    3676             :   // using a temporary BasicLayerManager.
    3677          30 :   BasicLayerManager* basic = static_cast<BasicLayerManager*>(aManager);
    3678          60 :   RefPtr<gfxContext> context = aContext;
    3679             : #ifdef MOZ_DUMP_PAINTING
    3680          30 :   int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
    3681             :   nsIntRect itemVisibleRect =
    3682          30 :     aItem->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel);
    3683             : 
    3684          60 :   RefPtr<DrawTarget> tempDT;
    3685          30 :   if (gfxEnv::DumpPaint()) {
    3686           0 :     tempDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
    3687           0 :                                       itemVisibleRect.Size(),
    3688           0 :                                       SurfaceFormat::B8G8R8A8);
    3689           0 :     if (tempDT) {
    3690           0 :       context = gfxContext::CreateOrNull(tempDT);
    3691           0 :       if (!context) {
    3692             :         // Leave this as crash, it's in the debugging code, we want to know
    3693           0 :         gfxDevCrash(LogReason::InvalidContext) << "PaintInactive context problem " << gfx::hexa(tempDT);
    3694           0 :         return;
    3695             :       }
    3696           0 :       context->SetMatrix(gfxMatrix::Translation(-itemVisibleRect.x,
    3697           0 :                                                 -itemVisibleRect.y));
    3698             :     }
    3699             :   }
    3700             : #endif
    3701          30 :   basic->BeginTransaction();
    3702          30 :   basic->SetTarget(context);
    3703             : 
    3704          30 :   if (aItem->GetType() == nsDisplayItem::TYPE_MASK) {
    3705           5 :     static_cast<nsDisplayMask*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
    3706           5 :     if (basic->InTransaction()) {
    3707           0 :       basic->AbortTransaction();
    3708             :     }
    3709          25 :   } else if (aItem->GetType() == nsDisplayItem::TYPE_FILTER){
    3710           0 :     static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
    3711           0 :     if (basic->InTransaction()) {
    3712           0 :       basic->AbortTransaction();
    3713             :     }
    3714             :   } else {
    3715          25 :     basic->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aBuilder);
    3716             :   }
    3717          30 :   FrameLayerBuilder *builder = static_cast<FrameLayerBuilder*>(basic->GetUserData(&gLayerManagerLayerBuilder));
    3718          30 :   if (builder) {
    3719          30 :     builder->DidEndTransaction();
    3720             :   }
    3721             : 
    3722          30 :   basic->SetTarget(nullptr);
    3723             : 
    3724             : #ifdef MOZ_DUMP_PAINTING
    3725          30 :   if (gfxEnv::DumpPaint() && tempDT) {
    3726           0 :     RefPtr<SourceSurface> surface = tempDT->Snapshot();
    3727           0 :     DumpPaintedImage(aItem, surface);
    3728             : 
    3729           0 :     DrawTarget* drawTarget = aContext->GetDrawTarget();
    3730           0 :     Rect rect(itemVisibleRect.x, itemVisibleRect.y,
    3731           0 :               itemVisibleRect.width, itemVisibleRect.height);
    3732           0 :     drawTarget->DrawSurface(surface, rect, Rect(Point(0,0), rect.Size()));
    3733             : 
    3734           0 :     aItem->SetPainted();
    3735             :   }
    3736             : #endif
    3737             : }
    3738             : 
    3739             : /**
    3740             :  * Chooses a single active scrolled root for the entire display list, used
    3741             :  * when we are flattening layers.
    3742             :  */
    3743             : bool
    3744           0 : ContainerState::ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
    3745             :                                            AnimatedGeometryRoot** aAnimatedGeometryRoot,
    3746             :                                            const ActiveScrolledRoot** aASR)
    3747             : {
    3748           0 :   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
    3749           0 :     LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
    3750             :     // Don't use an item that won't be part of any PaintedLayers to pick the
    3751             :     // active scrolled root.
    3752           0 :     if (layerState == LAYER_ACTIVE_FORCE) {
    3753           0 :       continue;
    3754             :     }
    3755             : 
    3756             :     // Try using the actual active scrolled root of the backmost item, as that
    3757             :     // should result in the least invalidation when scrolling.
    3758           0 :     *aAnimatedGeometryRoot = item->GetAnimatedGeometryRoot();
    3759           0 :     *aASR = item->GetActiveScrolledRoot();
    3760           0 :     return true;
    3761             :   }
    3762           0 :   return false;
    3763             : }
    3764             : 
    3765             : nsRect
    3766         183 : ContainerState::GetDisplayPortForAnimatedGeometryRoot(AnimatedGeometryRoot* aAnimatedGeometryRoot)
    3767             : {
    3768         183 :   if (mLastDisplayPortAGR == aAnimatedGeometryRoot) {
    3769         144 :     return mLastDisplayPortRect;
    3770             :   }
    3771             : 
    3772          39 :   mLastDisplayPortAGR = aAnimatedGeometryRoot;
    3773             : 
    3774          39 :   nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(*aAnimatedGeometryRoot);
    3775          39 :   if (sf == nullptr || nsLayoutUtils::UsesAsyncScrolling(*aAnimatedGeometryRoot)) {
    3776          39 :     mLastDisplayPortRect = nsRect();
    3777          39 :     return mLastDisplayPortRect;
    3778             :   }
    3779             : 
    3780             :   bool usingDisplayport =
    3781           0 :     nsLayoutUtils::GetDisplayPort((*aAnimatedGeometryRoot)->GetContent(), &mLastDisplayPortRect,
    3782           0 :                                   RelativeTo::ScrollFrame);
    3783           0 :   if (!usingDisplayport) {
    3784             :     // No async scrolling, so all that matters is that the layer contents
    3785             :     // cover the scrollport.
    3786           0 :     mLastDisplayPortRect = sf->GetScrollPortRect();
    3787             :   }
    3788           0 :   nsIFrame* scrollFrame = do_QueryFrame(sf);
    3789           0 :   mLastDisplayPortRect += scrollFrame->GetOffsetToCrossDoc(mContainerReferenceFrame);
    3790           0 :   return mLastDisplayPortRect;
    3791             : }
    3792             : 
    3793             : nsIntRegion
    3794        1350 : ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem,
    3795             :                                   AnimatedGeometryRoot* aAnimatedGeometryRoot,
    3796             :                                   const ActiveScrolledRoot* aASR,
    3797             :                                   const DisplayItemClip& aClip,
    3798             :                                   nsDisplayList* aList,
    3799             :                                   bool* aHideAllLayersBelow,
    3800             :                                   bool* aOpaqueForAnimatedGeometryRootParent)
    3801             : {
    3802             :   bool snapOpaque;
    3803        2700 :   nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque);
    3804        1350 :   if (opaque.IsEmpty()) {
    3805        1165 :     return nsIntRegion();
    3806             :   }
    3807             : 
    3808         370 :   nsIntRegion opaquePixels;
    3809         370 :   nsRegion opaqueClipped;
    3810         370 :   for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
    3811             :     opaqueClipped.Or(opaqueClipped,
    3812         185 :                      aClip.ApproximateIntersectInward(iter.Get()));
    3813             :   }
    3814         553 :   if (aAnimatedGeometryRoot == mContainerAnimatedGeometryRoot &&
    3815         368 :       aASR == mContainerASR &&
    3816         183 :       opaqueClipped.Contains(mContainerBounds)) {
    3817          52 :     *aHideAllLayersBelow = true;
    3818          52 :     aList->SetIsOpaque();
    3819             :   }
    3820             :   // Add opaque areas to the "exclude glass" region. Only do this when our
    3821             :   // container layer is going to be the rootmost layer, otherwise transforms
    3822             :   // etc will mess us up (and opaque contributions from other containers are
    3823             :   // not needed).
    3824         185 :   if (!nsLayoutUtils::GetCrossDocParentFrame(mContainerFrame)) {
    3825         172 :     mBuilder->AddWindowOpaqueRegion(opaqueClipped);
    3826             :   }
    3827         185 :   opaquePixels = ScaleRegionToInsidePixels(opaqueClipped, snapOpaque);
    3828             : 
    3829         185 :   if (IsInInactiveLayer()) {
    3830           2 :     return opaquePixels;
    3831             :   }
    3832             : 
    3833             :   const nsRect& displayport =
    3834         366 :     GetDisplayPortForAnimatedGeometryRoot(aAnimatedGeometryRoot);
    3835         549 :   if (!displayport.IsEmpty() &&
    3836         183 :       opaquePixels.Contains(ScaleRegionToNearestPixels(displayport))) {
    3837           0 :     *aOpaqueForAnimatedGeometryRootParent = true;
    3838             :   }
    3839         183 :   return opaquePixels;
    3840             : }
    3841             : 
    3842             : Maybe<size_t>
    3843           0 : ContainerState::SetupMaskLayerForScrolledClip(Layer* aLayer,
    3844             :                                               const DisplayItemClip& aClip)
    3845             : {
    3846           0 :   if (aClip.GetRoundedRectCount() > 0) {
    3847           0 :     Maybe<size_t> maskLayerIndex = Some(aLayer->GetAncestorMaskLayerCount());
    3848           0 :     if (RefPtr<Layer> maskLayer = CreateMaskLayer(aLayer, aClip, maskLayerIndex,
    3849           0 :                                                   aClip.GetRoundedRectCount())) {
    3850           0 :       aLayer->AddAncestorMaskLayer(maskLayer);
    3851           0 :       return maskLayerIndex;
    3852             :     }
    3853             :     // Fall through to |return Nothing()|.
    3854             :   }
    3855           0 :   return Nothing();
    3856             : }
    3857             : 
    3858             : static const ActiveScrolledRoot*
    3859           0 : GetASRForPerspective(const ActiveScrolledRoot* aASR, nsIFrame* aPerspectiveFrame)
    3860             : {
    3861           0 :   for (const ActiveScrolledRoot* asr = aASR; asr; asr = asr->mParent) {
    3862           0 :     nsIFrame* scrolledFrame = asr->mScrollableFrame->GetScrolledFrame();
    3863           0 :     if (nsLayoutUtils::IsAncestorFrameCrossDoc(scrolledFrame, aPerspectiveFrame)) {
    3864           0 :       return asr;
    3865             :     }
    3866             :   }
    3867           0 :   return nullptr;
    3868             : }
    3869             : 
    3870             : void
    3871           0 : ContainerState::SetupMaskLayerForCSSMask(Layer* aLayer,
    3872             :                                          nsDisplayMask* aMaskItem)
    3873             : {
    3874           0 :   MOZ_ASSERT(mManager->IsCompositingCheap());
    3875             : 
    3876             :   RefPtr<ImageLayer> maskLayer =
    3877           0 :     CreateOrRecycleMaskImageLayerFor(MaskLayerKey(aLayer, Nothing()),
    3878           0 :       [](Layer* aMaskLayer)
    3879             :       {
    3880           0 :         aMaskLayer->SetUserData(&gCSSMaskLayerUserData,
    3881           0 :                                 new CSSMaskLayerUserData());
    3882           0 :       }
    3883           0 :     );
    3884             : 
    3885             :   CSSMaskLayerUserData* oldUserData =
    3886           0 :     static_cast<CSSMaskLayerUserData*>(maskLayer->GetUserData(&gCSSMaskLayerUserData));
    3887             : 
    3888             :   bool snap;
    3889           0 :   nsRect bounds = aMaskItem->GetBounds(mBuilder, &snap);
    3890           0 :   nsIntRect itemRect = ScaleToOutsidePixels(bounds, snap);
    3891             : 
    3892             :   // Setup mask layer offset.
    3893             :   // We do not repaint mask for mask position change, so update base transform
    3894             :   // each time is required.
    3895           0 :   Matrix4x4 matrix;
    3896           0 :   matrix.PreTranslate(itemRect.x, itemRect.y, 0);
    3897           0 :   matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
    3898           0 :   maskLayer->SetBaseTransform(matrix);
    3899             : 
    3900           0 :   nsPoint maskLayerOffset = aMaskItem->ToReferenceFrame() - bounds.TopLeft();
    3901             : 
    3902           0 :   CSSMaskLayerUserData newUserData(aMaskItem->Frame(), itemRect, maskLayerOffset);
    3903           0 :   nsRect dirtyRect;
    3904           0 :   if (!aMaskItem->IsInvalid(dirtyRect) && *oldUserData == newUserData) {
    3905           0 :     aLayer->SetMaskLayer(maskLayer);
    3906           0 :     return;
    3907             :   }
    3908             : 
    3909           0 :   int32_t maxSize = mManager->GetMaxTextureSize();
    3910           0 :   IntSize surfaceSize(std::min(itemRect.width, maxSize),
    3911           0 :                       std::min(itemRect.height, maxSize));
    3912             : 
    3913           0 :   if (surfaceSize.IsEmpty()) {
    3914             :     // Return early if we know that the size of this mask surface is empty.
    3915           0 :     return;
    3916             :   }
    3917             : 
    3918           0 :   MaskImageData imageData(surfaceSize, mManager);
    3919           0 :   RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
    3920           0 :   if (!dt || !dt->IsValid()) {
    3921           0 :     NS_WARNING("Could not create DrawTarget for mask layer.");
    3922           0 :     return;
    3923             :   }
    3924             : 
    3925           0 :   RefPtr<gfxContext> maskCtx = gfxContext::CreateOrNull(dt);
    3926           0 :   maskCtx->SetMatrix(gfxMatrix::Translation(-itemRect.TopLeft()));
    3927           0 :   maskCtx->Multiply(gfxMatrix::Scaling(mParameters.mXScale, mParameters.mYScale));
    3928             : 
    3929           0 :   bool isPaintFinished = aMaskItem->PaintMask(mBuilder, maskCtx);
    3930             : 
    3931             :   RefPtr<ImageContainer> imgContainer =
    3932           0 :     imageData.CreateImageAndImageContainer();
    3933           0 :   if (!imgContainer) {
    3934           0 :     return;
    3935             :   }
    3936           0 :   maskLayer->SetContainer(imgContainer);
    3937             : 
    3938           0 :   if (isPaintFinished) {
    3939           0 :     *oldUserData = Move(newUserData);
    3940             :   }
    3941           0 :   aLayer->SetMaskLayer(maskLayer);
    3942             : }
    3943             : 
    3944             : static bool
    3945          76 : IsScrollThumbLayer(nsDisplayItem* aItem)
    3946             : {
    3947         104 :   return aItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER &&
    3948         104 :          static_cast<nsDisplayOwnLayer*>(aItem)->IsScrollThumbLayer();
    3949             : }
    3950             : 
    3951             : /*
    3952             :  * Iterate through the non-clip items in aList and its descendants.
    3953             :  * For each item we compute the effective clip rect. Each item is assigned
    3954             :  * to a layer. We invalidate the areas in PaintedLayers where an item
    3955             :  * has moved from one PaintedLayer to another. Also,
    3956             :  * aState->mInvalidPaintedContent is invalidated in every PaintedLayer.
    3957             :  * We set the clip rect for items that generated their own layer, and
    3958             :  * create a mask layer to do any rounded rect clipping.
    3959             :  * (PaintedLayers don't need a clip rect on the layer, we clip the items
    3960             :  * individually when we draw them.)
    3961             :  * We set the visible rect for all layers, although the actual setting
    3962             :  * of visible rects for some PaintedLayers is deferred until the calling
    3963             :  * of ContainerState::Finish.
    3964             :  */
    3965             : void
    3966         239 : ContainerState::ProcessDisplayItems(nsDisplayList* aList)
    3967             : {
    3968         478 :   AUTO_PROFILER_LABEL("ContainerState::ProcessDisplayItems", GRAPHICS);
    3969             : 
    3970         239 :   AnimatedGeometryRoot* lastAnimatedGeometryRoot = mContainerAnimatedGeometryRoot;
    3971         239 :   const ActiveScrolledRoot* lastASR = mContainerASR;
    3972         239 :   nsPoint lastAGRTopLeft;
    3973         239 :   nsPoint topLeft(0,0);
    3974             : 
    3975             :   // When NO_COMPONENT_ALPHA is set, items will be flattened into a single
    3976             :   // layer, so we need to choose which active scrolled root to use for all
    3977             :   // items.
    3978         239 :   if (mFlattenToSingleLayer) {
    3979           0 :     if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot, &lastASR)) {
    3980           0 :       lastAGRTopLeft = (*lastAnimatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
    3981             :     }
    3982             :   }
    3983             : 
    3984         239 :   int32_t maxLayers = gfxPrefs::MaxActiveLayers();
    3985         239 :   int layerCount = 0;
    3986             : 
    3987         478 :   nsDisplayList savedItems;
    3988             :   nsDisplayItem* item;
    3989        4751 :   while ((item = aList->RemoveBottom()) != nullptr) {
    3990        2256 :     nsDisplayItem::Type itemType = item->GetType();
    3991             : 
    3992             :     // If the item is a event regions item, but is empty (has no regions in it)
    3993             :     // then we should just throw it out
    3994        2256 :     if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
    3995             :       nsDisplayLayerEventRegions* eventRegions =
    3996         509 :         static_cast<nsDisplayLayerEventRegions*>(item);
    3997         509 :       if (eventRegions->IsEmpty()) {
    3998          48 :         item->~nsDisplayItem();
    3999          48 :         continue;
    4000             :       }
    4001             :     }
    4002             : 
    4003             :     // Peek ahead to the next item and try merging with it or swapping with it
    4004             :     // if necessary.
    4005             :     nsDisplayItem* aboveItem;
    4006        2208 :     while ((aboveItem = aList->GetBottom()) != nullptr) {
    4007        1945 :       if (aboveItem->TryMerge(item)) {
    4008           0 :         aList->RemoveBottom();
    4009           0 :         item->~nsDisplayItem();
    4010           0 :         item = aboveItem;
    4011           0 :         itemType = item->GetType();
    4012             :       } else {
    4013        1945 :         break;
    4014             :       }
    4015             :     }
    4016             : 
    4017             :     nsDisplayList* itemSameCoordinateSystemChildren
    4018        2208 :       = item->GetSameCoordinateSystemChildren();
    4019        2208 :     if (item->ShouldFlattenAway(mBuilder)) {
    4020         349 :       aList->AppendToBottom(itemSameCoordinateSystemChildren);
    4021         349 :       item->~nsDisplayItem();
    4022         349 :       continue;
    4023             :     }
    4024             : 
    4025        1859 :     savedItems.AppendToTop(item);
    4026             : 
    4027        1859 :     NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
    4028             :       "items in a container layer should all have the same app units per dev pixel");
    4029             : 
    4030        1859 :     if (mBuilder->NeedToForceTransparentSurfaceForItem(item)) {
    4031           0 :       aList->SetNeedsTransparentSurface();
    4032             :     }
    4033             : 
    4034        1883 :     if (mParameters.mForEventsAndPluginsOnly && !item->GetChildren() &&
    4035          24 :         (itemType != nsDisplayItem::TYPE_LAYER_EVENT_REGIONS &&
    4036             :          itemType != nsDisplayItem::TYPE_PLUGIN)) {
    4037          24 :       continue;
    4038             :     }
    4039             : 
    4040        1835 :     LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
    4041        1995 :     if (layerState == LAYER_INACTIVE &&
    4042         160 :         nsDisplayItem::ForceActiveLayers()) {
    4043           0 :       layerState = LAYER_ACTIVE;
    4044             :     }
    4045             : 
    4046             :     bool forceInactive;
    4047             :     AnimatedGeometryRoot* animatedGeometryRoot;
    4048        1835 :     const ActiveScrolledRoot* itemASR = nullptr;
    4049        1835 :     const DisplayItemClipChain* layerClipChain = nullptr;
    4050        1835 :     if (mFlattenToSingleLayer && layerState != LAYER_ACTIVE_FORCE) {
    4051           0 :       forceInactive = true;
    4052           0 :       animatedGeometryRoot = lastAnimatedGeometryRoot;
    4053           0 :       itemASR = lastASR;
    4054           0 :       topLeft = lastAGRTopLeft;
    4055           0 :       item->FuseClipChainUpTo(mBuilder, mContainerASR);
    4056             :     } else {
    4057        1835 :       forceInactive = false;
    4058        1835 :       if (mManager->IsWidgetLayerManager()) {
    4059        1513 :         animatedGeometryRoot = item->GetAnimatedGeometryRoot();
    4060        1513 :         itemASR = item->GetActiveScrolledRoot();
    4061        1513 :         const DisplayItemClipChain* itemClipChain = item->GetClipChain();
    4062        1513 :         if (itemClipChain && itemClipChain->mASR == itemASR &&
    4063             :             itemType != nsDisplayItem::TYPE_STICKY_POSITION) {
    4064        1239 :           layerClipChain = itemClipChain->mParent;
    4065             :         } else {
    4066         274 :           layerClipChain = itemClipChain;
    4067             :         }
    4068             :       } else {
    4069             :         // For inactive layer subtrees, splitting content into PaintedLayers
    4070             :         // based on animated geometry roots is pointless. It's more efficient
    4071             :         // to build the minimum number of layers.
    4072         322 :         animatedGeometryRoot = mContainerAnimatedGeometryRoot;
    4073         322 :         itemASR = mContainerASR;
    4074         322 :         item->FuseClipChainUpTo(mBuilder, mContainerASR);
    4075             :       }
    4076        1835 :       topLeft = (*animatedGeometryRoot)->GetOffsetToCrossDoc(mContainerReferenceFrame);
    4077             :     }
    4078             : 
    4079             :     const ActiveScrolledRoot* scrollMetadataASR =
    4080        1835 :         layerClipChain ? ActiveScrolledRoot::PickDescendant(itemASR, layerClipChain->mASR) : itemASR;
    4081             : 
    4082             :     bool snap;
    4083        3670 :     nsRect itemContent = item->GetBounds(mBuilder, &snap);
    4084        1835 :     if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
    4085             :       nsDisplayLayerEventRegions* eventRegions =
    4086         461 :         static_cast<nsDisplayLayerEventRegions*>(item);
    4087         461 :       itemContent = eventRegions->GetHitRegionBounds(mBuilder, &snap);
    4088             :     }
    4089        1835 :     nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
    4090        1859 :     bool prerenderedTransform = itemType == nsDisplayItem::TYPE_TRANSFORM &&
    4091        1859 :         static_cast<nsDisplayTransform*>(item)->MayBeAnimated(mBuilder);
    4092        1835 :     ParentLayerIntRect clipRect;
    4093        1835 :     const DisplayItemClip& itemClip = item->GetClip();
    4094        1835 :     if (itemClip.HasClip()) {
    4095        1507 :       itemContent.IntersectRect(itemContent, itemClip.GetClipRect());
    4096        1507 :       clipRect = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(itemClip.GetClipRect()));
    4097        1507 :       if (!prerenderedTransform) {
    4098        1507 :         itemDrawRect.IntersectRect(itemDrawRect, clipRect.ToUnknownRect());
    4099             :       }
    4100        1507 :       clipRect.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset));
    4101             :     }
    4102             : #ifdef DEBUG
    4103        3670 :     nsRect bounds = itemContent;
    4104             :     bool dummy;
    4105        1835 :     if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
    4106         461 :       bounds = item->GetBounds(mBuilder, &dummy);
    4107         461 :       if (itemClip.HasClip()) {
    4108         411 :         bounds.IntersectRect(bounds, itemClip.GetClipRect());
    4109             :       }
    4110             :     }
    4111        1835 :     if (!bounds.IsEmpty()) {
    4112        1326 :       if (itemASR != mContainerASR) {
    4113           3 :         const DisplayItemClip* clip = DisplayItemClipChain::ClipForASR(item->GetClipChain(), mContainerASR);
    4114           3 :         MOZ_ASSERT(clip || gfxPrefs::LayoutUseContainersForRootFrames(),
    4115             :                    "the item should have finite bounds with respect to mContainerASR.");
    4116           3 :         if (clip) {
    4117           3 :           bounds = clip->GetClipRect();
    4118             :         }
    4119             :       }
    4120             :     }
    4121        1835 :     ((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, bounds);
    4122             : #endif
    4123             : 
    4124        1835 :     nsIntRect itemVisibleRect = itemDrawRect;
    4125             :     // We haven't computed visibility at this point, so item->GetVisibleRect()
    4126             :     // is just the dirty rect that item was initialized with. We intersect it
    4127             :     // with the clipped item bounds to get a tighter visible rect.
    4128        1835 :     if (!prerenderedTransform) {
    4129             :       itemVisibleRect = itemVisibleRect.Intersect(
    4130        1835 :         ScaleToOutsidePixels(item->GetVisibleRect(), false));
    4131             :     }
    4132             : 
    4133        1835 :     if (maxLayers != -1 && layerCount >= maxLayers) {
    4134           0 :       forceInactive = true;
    4135             :     }
    4136             : 
    4137             :     // Assign the item to a layer
    4138        3618 :     if (layerState == LAYER_ACTIVE_FORCE ||
    4139        3830 :         (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) ||
    4140        3518 :         (!forceInactive &&
    4141        1759 :          (layerState == LAYER_ACTIVE_EMPTY ||
    4142             :           layerState == LAYER_ACTIVE))) {
    4143             : 
    4144          76 :       layerCount++;
    4145             : 
    4146             :       // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
    4147             :       // We should never see an empty layer with any visible content!
    4148          76 :       NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
    4149             :                    itemVisibleRect.IsEmpty(),
    4150             :                    "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
    4151             : 
    4152             :       // As long as the new layer isn't going to be a PaintedLayer,
    4153             :       // InvalidateForLayerChange doesn't need the new layer pointer.
    4154             :       // We also need to check the old data now, because BuildLayer
    4155             :       // can overwrite it.
    4156          76 :       InvalidateForLayerChange(item, nullptr);
    4157             : 
    4158             :       // If the item would have its own layer but is invisible, just hide it.
    4159             :       // Note that items without their own layers can't be skipped this
    4160             :       // way, since their PaintedLayer may decide it wants to draw them
    4161             :       // into its buffer even if they're currently covered.
    4162          76 :       if (itemVisibleRect.IsEmpty() &&
    4163           0 :           !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
    4164           0 :         continue;
    4165             :       }
    4166             : 
    4167             :       // 3D-transformed layers don't necessarily draw in the order in which
    4168             :       // they're added to their parent container layer.
    4169         100 :       bool mayDrawOutOfOrder = itemType == nsDisplayItem::TYPE_TRANSFORM &&
    4170          48 :         (item->Frame()->Combines3DTransformWithAncestors() ||
    4171         100 :          item->Frame()->Extend3DContext());
    4172             : 
    4173             :       // Let mPaintedLayerDataTree know about this item, so that
    4174             :       // FindPaintedLayerFor and FindOpaqueBackgroundColor are aware of this
    4175             :       // item, even though it's not in any PaintedLayerDataStack.
    4176             :       // Ideally we'd only need the "else" case here and have
    4177             :       // mPaintedLayerDataTree figure out the right clip from the animated
    4178             :       // geometry root that we give it, but it can't easily figure about
    4179             :       // overflow:hidden clips on ancestors just by looking at the frame.
    4180             :       // So we'll do a little hand holding and pass the clip instead of the
    4181             :       // visible rect for the two important cases.
    4182          76 :       nscolor uniformColor = NS_RGBA(0,0,0,0);
    4183          76 :       nscolor* uniformColorPtr = (mayDrawOutOfOrder || IsInInactiveLayer()) ? nullptr :
    4184          76 :                                                                               &uniformColor;
    4185          76 :       nsIntRect clipRectUntyped;
    4186          76 :       nsIntRect* clipPtr = nullptr;
    4187          76 :       if (itemClip.HasClip()) {
    4188          63 :         clipRectUntyped = clipRect.ToUnknownRect();
    4189          63 :         clipPtr = &clipRectUntyped;
    4190             :       }
    4191             : 
    4192          76 :       bool hasScrolledClip = layerClipChain && layerClipChain->mClip.HasClip() &&
    4193           0 :         (!ActiveScrolledRoot::IsAncestor(layerClipChain->mASR, itemASR) ||
    4194          76 :          itemType == nsDisplayItem::TYPE_STICKY_POSITION);
    4195             : 
    4196          76 :       if (hasScrolledClip) {
    4197             :         // If the clip is scrolled, reserve just the area of the clip for
    4198             :         // layerization, so that elements outside the clip can still merge
    4199             :         // into the same layer.
    4200           0 :         const ActiveScrolledRoot* clipASR = layerClipChain->mASR;
    4201           0 :         AnimatedGeometryRoot* clipAGR = mBuilder->AnimatedGeometryRootForASR(clipASR);
    4202             :         nsIntRect scrolledClipRect =
    4203           0 :           ScaleToNearestPixels(layerClipChain->mClip.GetClipRect()) + mParameters.mOffset;
    4204           0 :         mPaintedLayerDataTree.AddingOwnLayer(clipAGR,
    4205             :                                              &scrolledClipRect,
    4206           0 :                                              uniformColorPtr);
    4207         152 :       } else if (item->ShouldFixToViewport(mBuilder) && itemClip.HasClip() &&
    4208          76 :                  item->AnimatedGeometryRootForScrollMetadata() != animatedGeometryRoot &&
    4209           0 :                  !nsLayoutUtils::UsesAsyncScrolling(item->Frame())) {
    4210             :         // This is basically the same as the case above, but for the non-APZ
    4211             :         // case. At the moment, when APZ is off, there is only the root ASR
    4212             :         // (because scroll frames without display ports don't create ASRs) and
    4213             :         // the whole clip chain is always just one fused clip.
    4214             :         // Bug 1336516 aims to change that and to remove this workaround.
    4215           0 :         AnimatedGeometryRoot* clipAGR = item->AnimatedGeometryRootForScrollMetadata();
    4216             :         nsIntRect scrolledClipRect =
    4217           0 :           ScaleToNearestPixels(itemClip.GetClipRect()) + mParameters.mOffset;
    4218           0 :         mPaintedLayerDataTree.AddingOwnLayer(clipAGR,
    4219             :                                              &scrolledClipRect,
    4220           0 :                                              uniformColorPtr);
    4221          76 :       } else if (IsScrollThumbLayer(item) && mManager->IsWidgetLayerManager()) {
    4222             :         // For scrollbar thumbs, the clip we care about is the clip added by the
    4223             :         // slider frame.
    4224           0 :         mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot->mParentAGR,
    4225             :                                              clipPtr,
    4226           0 :                                              uniformColorPtr);
    4227          76 :       } else if (prerenderedTransform && mManager->IsWidgetLayerManager()) {
    4228           0 :         if (animatedGeometryRoot->mParentAGR) {
    4229           0 :           mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot->mParentAGR,
    4230             :                                                clipPtr,
    4231           0 :                                                uniformColorPtr);
    4232             :         } else {
    4233           0 :           mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot,
    4234             :                                                nullptr,
    4235           0 :                                                uniformColorPtr);
    4236             :         }
    4237             :       } else {
    4238             :         // Using itemVisibleRect here isn't perfect. itemVisibleRect can be
    4239             :         // larger or smaller than the potential bounds of item's contents in
    4240             :         // animatedGeometryRoot: It's too large if there's a clipped display
    4241             :         // port somewhere among item's contents (see bug 1147673), and it can
    4242             :         // be too small if the contents can move, because it only looks at the
    4243             :         // contents' current bounds and doesn't anticipate any animations.
    4244             :         // Time will tell whether this is good enough, or whether we need to do
    4245             :         // something more sophisticated here.
    4246          76 :         mPaintedLayerDataTree.AddingOwnLayer(animatedGeometryRoot,
    4247         152 :                                              &itemVisibleRect, uniformColorPtr);
    4248             :       }
    4249             : 
    4250          76 :       ContainerLayerParameters params = mParameters;
    4251          76 :       params.mBackgroundColor = uniformColor;
    4252          76 :       params.mLayerCreationHint = GetLayerCreationHint(animatedGeometryRoot);
    4253          76 :       params.mScrollMetadataASR = ActiveScrolledRoot::PickDescendant(mContainerScrollMetadataASR, scrollMetadataASR);
    4254         152 :       params.mCompositorASR = params.mScrollMetadataASR != mContainerScrollMetadataASR
    4255          76 :                                 ? params.mScrollMetadataASR
    4256             :                                 : mContainerCompositorASR;
    4257          76 :       if (itemType == nsDisplayItem::TYPE_FIXED_POSITION) {
    4258           0 :         params.mCompositorASR = itemASR;
    4259             :       }
    4260             : 
    4261          76 :       if (itemType == nsDisplayItem::TYPE_PERSPECTIVE) {
    4262             :         // Perspective items have a single child item, an nsDisplayTransform.
    4263             :         // If the perspective item is scrolled, but the perspective-inducing
    4264             :         // frame is outside the scroll frame (indicated by item->Frame()
    4265             :         // being outside that scroll frame), we have to take special care to
    4266             :         // make APZ scrolling work properly. APZ needs us to put the scroll
    4267             :         // frame's FrameMetrics on our child transform ContainerLayer instead.
    4268             :         // It's worth investigating whether this ASR adjustment can be done at
    4269             :         // display item creation time.
    4270           0 :         scrollMetadataASR = GetASRForPerspective(scrollMetadataASR, item->Frame());
    4271           0 :         params.mScrollMetadataASR = scrollMetadataASR;
    4272           0 :         itemASR = scrollMetadataASR;
    4273             :       }
    4274             : 
    4275             :       // Just use its layer.
    4276             :       // Set layerContentsVisibleRect.width/height to -1 to indicate we
    4277             :       // currently don't know. If BuildContainerLayerFor gets called by
    4278             :       // item->BuildLayer, this will be set to a proper rect.
    4279          76 :       nsIntRect layerContentsVisibleRect(0, 0, -1, -1);
    4280          76 :       params.mLayerContentsVisibleRect = &layerContentsVisibleRect;
    4281         152 :       RefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, params);
    4282          76 :       if (!ownLayer) {
    4283           0 :         continue;
    4284             :       }
    4285             : 
    4286          76 :       NS_ASSERTION(!ownLayer->AsPaintedLayer(),
    4287             :                    "Should never have created a dedicated Painted layer!");
    4288             : 
    4289          76 :       if (item->BackfaceIsHidden()) {
    4290           0 :         ownLayer->SetContentFlags(ownLayer->GetContentFlags() |
    4291           0 :                                   Layer::CONTENT_BACKFACE_HIDDEN);
    4292             :       } else {
    4293          76 :         ownLayer->SetContentFlags(ownLayer->GetContentFlags() &
    4294          76 :                                   ~Layer::CONTENT_BACKFACE_HIDDEN);
    4295             :       }
    4296             : 
    4297         152 :       nsRect invalid;
    4298          76 :       if (item->IsInvalid(invalid)) {
    4299          34 :         ownLayer->SetInvalidRectToVisibleRegion();
    4300             :       }
    4301             : 
    4302             :       // If it's not a ContainerLayer, we need to apply the scale transform
    4303             :       // ourselves.
    4304          76 :       if (!ownLayer->AsContainerLayer()) {
    4305           0 :         ownLayer->SetPostScale(mParameters.mXScale,
    4306           0 :                                mParameters.mYScale);
    4307             :       }
    4308             : 
    4309             :       // Update that layer's clip and visible rects.
    4310          76 :       NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
    4311          76 :       NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
    4312             :                    "We shouldn't have a FrameLayerBuilder-managed layer here!");
    4313          76 :       NS_ASSERTION(itemClip.HasClip() ||
    4314             :                    itemClip.GetRoundedRectCount() == 0,
    4315             :                    "If we have rounded rects, we must have a clip rect");
    4316             : 
    4317             :       // It has its own layer. Update that layer's clip and visible rects.
    4318          76 :       ownLayer->SetClipRect(Nothing());
    4319          76 :       ownLayer->SetScrolledClip(Nothing());
    4320          76 :       ownLayer->SetAncestorMaskLayers({});
    4321          76 :       if (itemClip.HasClip()) {
    4322          63 :         ownLayer->SetClipRect(Some(clipRect));
    4323             : 
    4324             :         // rounded rectangle clipping using mask layers
    4325             :         // (must be done after visible rect is set on layer)
    4326          63 :         if (itemClip.GetRoundedRectCount() > 0) {
    4327           0 :           SetupMaskLayer(ownLayer, itemClip);
    4328             :         }
    4329             :       }
    4330             : 
    4331          76 :       if (hasScrolledClip) {
    4332           0 :         const DisplayItemClip& scrolledClip = layerClipChain->mClip;
    4333           0 :         LayerClip scrolledLayerClip;
    4334           0 :         scrolledLayerClip.SetClipRect(ViewAs<ParentLayerPixel>(
    4335           0 :           ScaleToNearestPixels(scrolledClip.GetClipRect()) + mParameters.mOffset));
    4336           0 :         if (scrolledClip.GetRoundedRectCount() > 0) {
    4337             :           scrolledLayerClip.SetMaskLayerIndex(
    4338           0 :               SetupMaskLayerForScrolledClip(ownLayer.get(), scrolledClip));
    4339             :         }
    4340           0 :         ownLayer->SetScrolledClip(Some(scrolledLayerClip));
    4341             :       }
    4342             : 
    4343          76 :       if (item->GetType() == nsDisplayItem::TYPE_MASK) {
    4344           0 :         MOZ_ASSERT(itemClip.GetRoundedRectCount() == 0);
    4345             : 
    4346           0 :         nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
    4347           0 :         SetupMaskLayerForCSSMask(ownLayer, maskItem);
    4348             : 
    4349           0 :         nsDisplayItem* next = aList->GetBottom();
    4350           0 :         if (next && next->GetType() == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
    4351             :           // Since we do build a layer for mask, there is no need for this
    4352             :           // scroll info layer anymore.
    4353           0 :           aList->RemoveBottom();
    4354           0 :           next->~nsDisplayItem();
    4355             :         }
    4356             :       }
    4357             : 
    4358             :       // Convert the visible rect to a region and give the item
    4359             :       // a chance to try restrict it further.
    4360         152 :       nsIntRegion itemVisibleRegion = itemVisibleRect;
    4361         152 :       nsRegion tightBounds = item->GetTightBounds(mBuilder, &snap);
    4362          76 :       if (!tightBounds.IsEmpty()) {
    4363           0 :         itemVisibleRegion.AndWith(ScaleToOutsidePixels(tightBounds, snap));
    4364             :       }
    4365             : 
    4366          76 :       ContainerLayer* oldContainer = ownLayer->GetParent();
    4367          76 :       if (oldContainer && oldContainer != mContainerLayer) {
    4368           0 :         oldContainer->RemoveChild(ownLayer);
    4369             :       }
    4370          76 :       NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0,
    4371             :                    "Layer already in list???");
    4372             : 
    4373          76 :       NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
    4374          76 :       newLayerEntry->mLayer = ownLayer;
    4375          76 :       newLayerEntry->mAnimatedGeometryRoot = animatedGeometryRoot;
    4376          76 :       newLayerEntry->mASR = itemASR;
    4377          76 :       newLayerEntry->mScrollMetadataASR = scrollMetadataASR;
    4378          76 :       newLayerEntry->mClipChain = layerClipChain;
    4379          76 :       newLayerEntry->mLayerState = layerState;
    4380          76 :       if (itemType == nsDisplayItem::TYPE_FIXED_POSITION) {
    4381           0 :         newLayerEntry->mIsFixedToRootScrollFrame =
    4382           0 :           item->Frame()->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
    4383           0 :           nsLayoutUtils::IsReallyFixedPos(item->Frame());
    4384             :       }
    4385             : 
    4386             :       // Don't attempt to flatten compnent alpha layers that are within
    4387             :       // a forced active layer, or an active transform;
    4388          76 :       if (itemType == nsDisplayItem::TYPE_TRANSFORM ||
    4389             :           layerState == LAYER_ACTIVE_FORCE) {
    4390          76 :         newLayerEntry->mPropagateComponentAlphaFlattening = false;
    4391             :       }
    4392             : 
    4393          76 :       float contentXScale = 1.0f;
    4394          76 :       float contentYScale = 1.0f;
    4395          76 :       if (ContainerLayer* ownContainer = ownLayer->AsContainerLayer()) {
    4396          76 :         contentXScale = 1 / ownContainer->GetPreXScale();
    4397          76 :         contentYScale = 1 / ownContainer->GetPreYScale();
    4398             :       }
    4399             :       // nsDisplayTransform::BuildLayer must set layerContentsVisibleRect.
    4400             :       // We rely on this to ensure 3D transforms compute a reasonable
    4401             :       // layer visible region.
    4402          76 :       NS_ASSERTION(itemType != nsDisplayItem::TYPE_TRANSFORM ||
    4403             :                    layerContentsVisibleRect.width >= 0,
    4404             :                    "Transform items must set layerContentsVisibleRect!");
    4405          76 :       if (mLayerBuilder->IsBuildingRetainedLayers()) {
    4406          52 :         newLayerEntry->mLayerContentsVisibleRect = layerContentsVisibleRect;
    4407          52 :         if (itemType == nsDisplayItem::TYPE_PERSPECTIVE ||
    4408           0 :             (itemType == nsDisplayItem::TYPE_TRANSFORM &&
    4409           0 :              (item->Frame()->Extend3DContext() ||
    4410           0 :               item->Frame()->Combines3DTransformWithAncestors() ||
    4411           0 :               item->Frame()->HasPerspective()))) {
    4412             :           // Give untransformed visible region as outer visible region
    4413             :           // to avoid failure caused by singular transforms.
    4414           0 :           newLayerEntry->mUntransformedVisibleRegion = true;
    4415             :           newLayerEntry->mVisibleRegion =
    4416           0 :             item->GetVisibleRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel);
    4417             :         } else {
    4418          52 :           newLayerEntry->mVisibleRegion = itemVisibleRegion;
    4419             :         }
    4420         104 :         newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item,
    4421             :           animatedGeometryRoot, itemASR, itemClip, aList,
    4422             :           &newLayerEntry->mHideAllLayersBelow,
    4423          52 :           &newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
    4424             :       } else {
    4425             :         bool useChildrenVisible =
    4426          48 :           itemType == nsDisplayItem::TYPE_TRANSFORM &&
    4427          48 :           (item->Frame()->IsPreserve3DLeaf() ||
    4428          48 :            item->Frame()->HasPerspective());
    4429             :         const nsIntRegion &visible = useChildrenVisible ?
    4430          24 :           item->GetVisibleRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel):
    4431          72 :           itemVisibleRegion;
    4432             : 
    4433          48 :         SetOuterVisibleRegionForLayer(ownLayer, visible,
    4434          24 :             layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr,
    4435          24 :             useChildrenVisible);
    4436             :       }
    4437          76 :       if (itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
    4438           0 :         nsDisplayScrollInfoLayer* scrollItem = static_cast<nsDisplayScrollInfoLayer*>(item);
    4439           0 :         newLayerEntry->mOpaqueForAnimatedGeometryRootParent = false;
    4440             :         newLayerEntry->mBaseScrollMetadata =
    4441           0 :             scrollItem->ComputeScrollMetadata(ownLayer, mParameters);
    4442         152 :       } else if ((itemType == nsDisplayItem::TYPE_SUBDOCUMENT ||
    4443          76 :                   itemType == nsDisplayItem::TYPE_ZOOM ||
    4444          76 :                   itemType == nsDisplayItem::TYPE_RESOLUTION) &&
    4445           0 :                  gfxPrefs::LayoutUseContainersForRootFrames())
    4446             :       {
    4447             :         newLayerEntry->mBaseScrollMetadata =
    4448           0 :           static_cast<nsDisplaySubDocument*>(item)->ComputeScrollMetadata(ownLayer, mParameters);
    4449             :       }
    4450             : 
    4451             :       /**
    4452             :        * No need to allocate geometry for items that aren't
    4453             :        * part of a PaintedLayer.
    4454             :        */
    4455          76 :       mLayerBuilder->AddLayerDisplayItem(ownLayer, item, layerState, nullptr);
    4456             :     } else {
    4457             :       PaintedLayerData* paintedLayerData =
    4458        3518 :         mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain,
    4459             :                                                   itemVisibleRect,
    4460        1759 :                                                   item->Frame()->In3DContextAndBackfaceIsHidden(),
    4461         258 :                                                   [&]() {
    4462        1290 :           return NewPaintedLayerData(item, animatedGeometryRoot, itemASR, layerClipChain, scrollMetadataASR,
    4463         516 :                                      topLeft);
    4464        3307 :         });
    4465             : 
    4466        1759 :       if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
    4467             :         nsDisplayLayerEventRegions* eventRegions =
    4468         461 :             static_cast<nsDisplayLayerEventRegions*>(item);
    4469         461 :         paintedLayerData->AccumulateEventRegions(this, eventRegions);
    4470             :       } else {
    4471             :         // check to see if the new item has rounded rect clips in common with
    4472             :         // other items in the layer
    4473        1298 :         if (mManager->IsWidgetLayerManager()) {
    4474        1123 :           paintedLayerData->UpdateCommonClipCount(itemClip);
    4475             :         }
    4476             :         nsIntRegion opaquePixels = ComputeOpaqueRect(item,
    4477             :             animatedGeometryRoot, itemASR, itemClip, aList,
    4478             :             &paintedLayerData->mHideAllLayersBelow,
    4479        2596 :             &paintedLayerData->mOpaqueForAnimatedGeometryRootParent);
    4480        1298 :         MOZ_ASSERT(nsIntRegion(itemDrawRect).Contains(opaquePixels));
    4481        1298 :         opaquePixels.AndWith(itemVisibleRect);
    4482             :         paintedLayerData->Accumulate(this, item, opaquePixels,
    4483        1298 :             itemVisibleRect, itemClip, layerState);
    4484             : 
    4485        1298 :         if (!paintedLayerData->mLayer) {
    4486             :           // Try to recycle the old layer of this display item.
    4487             :           RefPtr<PaintedLayer> layer =
    4488         464 :             AttemptToRecyclePaintedLayer(animatedGeometryRoot, item, topLeft);
    4489         232 :           if (layer) {
    4490         113 :             paintedLayerData->mLayer = layer;
    4491             : 
    4492         113 :             NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
    4493             :                          "Layer already in list???");
    4494         113 :             mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget();
    4495             :           }
    4496             :         }
    4497             :       }
    4498             :     }
    4499             : 
    4500        2006 :     if (itemSameCoordinateSystemChildren &&
    4501         171 :         itemSameCoordinateSystemChildren->NeedsTransparentSurface()) {
    4502           0 :       aList->SetNeedsTransparentSurface();
    4503             :     }
    4504             :   }
    4505             : 
    4506         239 :   aList->AppendToTop(&savedItems);
    4507         239 : }
    4508             : 
    4509             : void
    4510        1374 : ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, PaintedLayer* aNewLayer)
    4511             : {
    4512        1374 :   NS_ASSERTION(aItem->GetPerFrameKey(),
    4513             :                "Display items that render using Thebes must have a key");
    4514        1374 :   nsDisplayItemGeometry* oldGeometry = nullptr;
    4515        1374 :   DisplayItemClip* oldClip = nullptr;
    4516        1374 :   Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip);
    4517        1374 :   if (aNewLayer != oldLayer && oldLayer) {
    4518             :     // The item has changed layers.
    4519             :     // Invalidate the old bounds in the old layer and new bounds in the new layer.
    4520          49 :     PaintedLayer* t = oldLayer->AsPaintedLayer();
    4521          49 :     if (t && oldGeometry) {
    4522             :       // Note that whenever the layer's scale changes, we invalidate the whole thing,
    4523             :       // so it doesn't matter whether we are using the old scale at last paint
    4524             :       // or a new scale here
    4525             : #ifdef MOZ_DUMP_PAINTING
    4526           0 :       if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    4527           0 :         printf_stderr("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), aItem->Frame(), t, aNewLayer);
    4528             :       }
    4529             : #endif
    4530           0 :       InvalidatePostTransformRegion(t,
    4531             :           oldGeometry->ComputeInvalidationRegion(),
    4532             :           *oldClip,
    4533           0 :           mLayerBuilder->GetLastPaintOffset(t));
    4534             :     }
    4535             :     // Clear the old geometry so that invalidation thinks the item has been
    4536             :     // added this paint.
    4537          49 :     mLayerBuilder->ClearCachedGeometry(aItem);
    4538          49 :     aItem->NotifyRenderingChanged();
    4539             :   }
    4540        1374 : }
    4541             : 
    4542             : void
    4543        1459 : FrameLayerBuilder::ComputeGeometryChangeForItem(DisplayItemData* aData)
    4544             : {
    4545        1459 :   nsDisplayItem *item = aData->mItem;
    4546        1459 :   PaintedLayer* paintedLayer = aData->mLayer->AsPaintedLayer();
    4547             :   // If aData->mOptLayer is presence, means this item has been optimized to the separate
    4548             :   // layer. Thus, skip geometry change calculation.
    4549        1459 :   if (aData->mOptLayer || !item || !paintedLayer) {
    4550         222 :     aData->EndUpdate();
    4551         222 :     return;
    4552             :   }
    4553             : 
    4554        2474 :   nsAutoPtr<nsDisplayItemGeometry> geometry;
    4555             : 
    4556             :   PaintedDisplayItemLayerUserData* layerData =
    4557        1237 :     static_cast<PaintedDisplayItemLayerUserData*>(aData->mLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
    4558        1237 :   nsPoint shift = layerData->mAnimatedGeometryRootOrigin - layerData->mLastAnimatedGeometryRootOrigin;
    4559             : 
    4560        1237 :   const DisplayItemClip& clip = item->GetClip();
    4561             : 
    4562             :   // If the frame is marked as invalidated, and didn't specify a rect to invalidate then we want to
    4563             :   // invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas.
    4564             :   // If we do get an invalid rect, then we want to add this on top of the change areas.
    4565        2474 :   nsRect invalid;
    4566        2474 :   nsRegion combined;
    4567        1237 :   bool notifyRenderingChanged = true;
    4568        1237 :   if (!aData->mGeometry) {
    4569             :     // This item is being added for the first time, invalidate its entire area.
    4570          71 :     geometry = item->AllocateGeometry(mDisplayListBuilder);
    4571          71 :     combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
    4572             : #ifdef MOZ_DUMP_PAINTING
    4573          71 :     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    4574           0 :       printf_stderr("Display item type %s(%p) added to layer %p!\n", item->Name(), item->Frame(), aData->mLayer.get());
    4575             :     }
    4576             : #endif
    4577        1166 :   } else if (aData->mIsInvalid || (item->IsInvalid(invalid) && invalid.IsEmpty())) {
    4578             :     // Layout marked item/frame as needing repainting (without an explicit rect), invalidate the entire old and new areas.
    4579          57 :     geometry = item->AllocateGeometry(mDisplayListBuilder);
    4580          57 :     combined = aData->mClip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
    4581          57 :     combined.MoveBy(shift);
    4582          57 :     combined.Or(combined, clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion()));
    4583             : #ifdef MOZ_DUMP_PAINTING
    4584          57 :     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    4585           0 :       printf_stderr("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", item->Name(), item->Frame(), aData->mLayer.get());
    4586             :     }
    4587             : #endif
    4588             :   } else {
    4589             :     // Let the display item check for geometry changes and decide what needs to be
    4590             :     // repainted.
    4591             : 
    4592        1109 :     const nsRegion& changedFrameInvalidations = aData->GetChangedFrameInvalidations();
    4593        1109 :     aData->mGeometry->MoveBy(shift);
    4594        1109 :     item->ComputeInvalidationRegion(mDisplayListBuilder, aData->mGeometry, &combined);
    4595             : 
    4596             :     // We have an optimization to cache the drawing of background-attachment: fixed canvas
    4597             :     // background images so we can scroll and just blit them when they are flattened into
    4598             :     // the same layer as scrolling content. NotifyRenderingChanged is only used to tell
    4599             :     // the canvas bg image item to purge this cache. We want to be careful not to accidentally
    4600             :     // purge the cache if we are just invalidating due to scrolling (ie the background image
    4601             :     // moves on the scrolling layer but it's rendering stays the same) so if
    4602             :     // AddOffsetAndComputeDifference is the only thing that will invalidate we skip the
    4603             :     // NotifyRenderingChanged call (ComputeInvalidationRegion for background images also calls
    4604             :     // NotifyRenderingChanged if anything changes).
    4605             :     // Only allocate a new geometry object if something actually changed, otherwise the existing
    4606             :     // one should be fine. We always reallocate for inactive layers, since these types don't
    4607             :     // implement ComputeInvalidateRegion (and rely on the ComputeDifferences call in
    4608             :     // AddPaintedDisplayItem instead).
    4609        1109 :     if (!combined.IsEmpty() || aData->mLayerState == LAYER_INACTIVE) {
    4610         172 :       geometry = item->AllocateGeometry(mDisplayListBuilder);
    4611        1871 :     } else if (aData->mClip == clip && invalid.IsEmpty() &&
    4612         934 :                changedFrameInvalidations.IsEmpty() == 0) {
    4613           0 :       notifyRenderingChanged = false;
    4614             :     }
    4615        1109 :     PaintedLayerItemsEntry* entry = mPaintedLayerItems.GetEntry(paintedLayer);
    4616        2218 :     aData->mClip.AddOffsetAndComputeDifference(entry->mCommonClipCount,
    4617             :                                                shift, aData->mGeometry->ComputeInvalidationRegion(),
    4618             :                                                clip, entry->mLastCommonClipCount,
    4619         172 :                                                geometry ? geometry->ComputeInvalidationRegion() :
    4620        2046 :                                                           aData->mGeometry->ComputeInvalidationRegion(),
    4621        1109 :                                                &combined);
    4622             : 
    4623             :     // Add in any rect that the frame specified
    4624        1109 :     combined.Or(combined, invalid);
    4625        1109 :     combined.Or(combined, changedFrameInvalidations);
    4626             : 
    4627             :     // Restrict invalidation to the clipped region
    4628        2218 :     nsRegion clipRegion;
    4629        1109 :     if (clip.ComputeRegionInClips(&aData->mClip, shift, &clipRegion)) {
    4630         920 :       combined.And(combined, clipRegion);
    4631             :     }
    4632             : #ifdef MOZ_DUMP_PAINTING
    4633        1109 :     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    4634           0 :       if (!combined.IsEmpty()) {
    4635           0 :         printf_stderr("Display item type %s(%p) (in layer %p) changed geometry!\n", item->Name(), item->Frame(), aData->mLayer.get());
    4636             :       }
    4637             :     }
    4638             : #endif
    4639             :   }
    4640        1237 :   if (!combined.IsEmpty()) {
    4641         175 :     if (notifyRenderingChanged) {
    4642         175 :       item->NotifyRenderingChanged();
    4643             :     }
    4644         175 :     InvalidatePostTransformRegion(paintedLayer,
    4645         350 :         combined.ScaleToOutsidePixels(layerData->mXScale, layerData->mYScale, layerData->mAppUnitsPerDevPixel),
    4646         175 :         layerData->mTranslation);
    4647             :   }
    4648             : 
    4649        1237 :   aData->EndUpdate(geometry);
    4650             : }
    4651             : 
    4652             : void
    4653        1298 : FrameLayerBuilder::AddPaintedDisplayItem(PaintedLayerData* aLayerData,
    4654             :                                         nsDisplayItem* aItem,
    4655             :                                         const DisplayItemClip& aClip,
    4656             :                                         ContainerState& aContainerState,
    4657             :                                         LayerState aLayerState,
    4658             :                                         const nsPoint& aTopLeft)
    4659             : {
    4660        1298 :   PaintedLayer* layer = aLayerData->mLayer;
    4661             :   PaintedDisplayItemLayerUserData* paintedData =
    4662             :     static_cast<PaintedDisplayItemLayerUserData*>
    4663        1298 :       (layer->GetUserData(&gPaintedDisplayItemLayerUserData));
    4664        2596 :   RefPtr<BasicLayerManager> tempManager;
    4665        1298 :   nsIntRect intClip;
    4666        1298 :   bool hasClip = false;
    4667        1298 :   if (aLayerState != LAYER_NONE) {
    4668         143 :     DisplayItemData *data = GetDisplayItemDataForManager(aItem, layer->Manager());
    4669         143 :     if (data) {
    4670         131 :       tempManager = data->mInactiveManager;
    4671             :     }
    4672         143 :     if (!tempManager) {
    4673          12 :       tempManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
    4674             :     }
    4675             : 
    4676             :     // We need to grab these before calling AddLayerDisplayItem because it will overwrite them.
    4677         286 :     nsRegion clip;
    4678         143 :     DisplayItemClip* oldClip = nullptr;
    4679         143 :     GetOldLayerFor(aItem, nullptr, &oldClip);
    4680         143 :     hasClip = aClip.ComputeRegionInClips(oldClip,
    4681         286 :                                          aTopLeft - paintedData->mLastAnimatedGeometryRootOrigin,
    4682         143 :                                          &clip);
    4683             : 
    4684         143 :     if (hasClip) {
    4685           0 :       intClip = clip.GetBounds().ScaleToOutsidePixels(paintedData->mXScale,
    4686             :                                                       paintedData->mYScale,
    4687           0 :                                                       paintedData->mAppUnitsPerDevPixel);
    4688             :     }
    4689             :   }
    4690             : 
    4691        1298 :   AddLayerDisplayItem(layer, aItem, aLayerState, tempManager);
    4692             : 
    4693        1298 :   PaintedLayerItemsEntry* entry = mPaintedLayerItems.PutEntry(layer);
    4694        1298 :   if (entry) {
    4695        1298 :     entry->mContainerLayerFrame = aContainerState.GetContainerFrame();
    4696        1298 :     if (entry->mContainerLayerGeneration == 0) {
    4697           0 :       entry->mContainerLayerGeneration = mContainerLayerGeneration;
    4698             :     }
    4699        1298 :     if (tempManager) {
    4700         143 :       FLB_LOG_PAINTED_LAYER_DECISION(aLayerData, "Creating nested FLB for item %p\n", aItem);
    4701         143 :       FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
    4702         143 :       layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData, &aClip);
    4703             : 
    4704         143 :       tempManager->BeginTransaction();
    4705         143 :       if (mRetainingManager) {
    4706         141 :         layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
    4707             :       }
    4708             : 
    4709         286 :       UniquePtr<LayerProperties> props(LayerProperties::CloneFrom(tempManager->GetRoot()));
    4710             :       RefPtr<Layer> tmpLayer =
    4711         286 :         aItem->BuildLayer(mDisplayListBuilder, tempManager, ContainerLayerParameters());
    4712             :       // We have no easy way of detecting if this transaction will ever actually get finished.
    4713             :       // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp
    4714         143 :       if (!tmpLayer) {
    4715           0 :         tempManager->EndTransaction(nullptr, nullptr);
    4716           0 :         tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
    4717           0 :         return;
    4718             :       }
    4719             : 
    4720             :       bool snap;
    4721             :       nsRect visibleRect =
    4722         286 :         aItem->GetVisibleRect().Intersect(aItem->GetBounds(mDisplayListBuilder, &snap));
    4723         286 :       nsIntRegion rgn = visibleRect.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel);
    4724             : 
    4725             :       // Convert the visible rect to a region and give the item
    4726             :       // a chance to try restrict it further.
    4727         286 :       nsRegion tightBounds = aItem->GetTightBounds(mDisplayListBuilder, &snap);
    4728         143 :       if (!tightBounds.IsEmpty()) {
    4729           0 :         rgn.AndWith(tightBounds.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel));
    4730             :       }
    4731         143 :       SetOuterVisibleRegion(tmpLayer, &rgn);
    4732             : 
    4733             :       // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
    4734             :       // stored in layerBuilder. Manually add it now.
    4735         143 :       if (mRetainingManager) {
    4736             : #ifdef DEBUG_DISPLAY_ITEM_DATA
    4737             :         LayerManagerData* parentLmd = static_cast<LayerManagerData*>
    4738             :           (layer->Manager()->GetUserData(&gLayerManagerUserData));
    4739             :         LayerManagerData* lmd = static_cast<LayerManagerData*>
    4740             :           (tempManager->GetUserData(&gLayerManagerUserData));
    4741             :         lmd->mParent = parentLmd;
    4742             : #endif
    4743         141 :         layerBuilder->StoreDataForFrame(aItem, tmpLayer, LAYER_ACTIVE);
    4744             :       }
    4745             : 
    4746         143 :       tempManager->SetRoot(tmpLayer);
    4747         143 :       layerBuilder->WillEndTransaction();
    4748         143 :       tempManager->AbortTransaction();
    4749             : 
    4750             : #ifdef MOZ_DUMP_PAINTING
    4751         143 :       if (gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint()) {
    4752           0 :         fprintf_stderr(gfxUtils::sDumpPaintFile, "Basic layer tree for painting contents of display item %s(%p):\n", aItem->Name(), aItem->Frame());
    4753           0 :         std::stringstream stream;
    4754           0 :         tempManager->Dump(stream, "", gfxEnv::DumpPaintToFile());
    4755           0 :         fprint_stderr(gfxUtils::sDumpPaintFile, stream);  // not a typo, fprint_stderr declared in LayersLogging.h
    4756             :       }
    4757             : #endif
    4758             : 
    4759         143 :       nsIntPoint offset = GetLastPaintOffset(layer) - GetTranslationForPaintedLayer(layer);
    4760         143 :       props->MoveBy(-offset);
    4761             :       // Effective transforms are needed by ComputeDifferences().
    4762         143 :       tmpLayer->ComputeEffectiveTransforms(Matrix4x4());
    4763         286 :       nsIntRegion invalid = props->ComputeDifferences(tmpLayer, nullptr);
    4764         143 :       if (aLayerState == LAYER_SVG_EFFECTS) {
    4765          14 :         invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(aItem->Frame(),
    4766             :                                                                         aItem->ToReferenceFrame(),
    4767           7 :                                                                         invalid);
    4768             :       }
    4769         143 :       if (!invalid.IsEmpty()) {
    4770             : #ifdef MOZ_DUMP_PAINTING
    4771          19 :         if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
    4772           0 :           printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->Frame(), layer);
    4773             :         }
    4774             : #endif
    4775          19 :         invalid.ScaleRoundOut(paintedData->mXScale, paintedData->mYScale);
    4776             : 
    4777          19 :         if (hasClip) {
    4778           0 :           invalid.And(invalid, intClip);
    4779             :         }
    4780             : 
    4781             :         InvalidatePostTransformRegion(layer, invalid,
    4782          19 :                                       GetTranslationForPaintedLayer(layer));
    4783             :       }
    4784             :     }
    4785             :     ClippedDisplayItem* cdi =
    4786        2596 :       entry->mItems.AppendElement(ClippedDisplayItem(aItem,
    4787        1298 :                                                      mContainerLayerGeneration));
    4788        1298 :     cdi->mInactiveLayerManager = tempManager;
    4789             :   }
    4790             : }
    4791             : 
    4792             : DisplayItemData*
    4793        1602 : FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer, LayerState aState)
    4794             : {
    4795        1602 :   DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager);
    4796        1602 :   if (oldData) {
    4797        1517 :     if (!oldData->mUsed) {
    4798        1348 :       oldData->BeginUpdate(aLayer, aState, mContainerLayerGeneration, aItem);
    4799             :     }
    4800        1517 :     return oldData;
    4801             :   }
    4802             : 
    4803             :   LayerManagerData* lmd = static_cast<LayerManagerData*>
    4804          85 :     (mRetainingManager->GetUserData(&gLayerManagerUserData));
    4805             : 
    4806             :   RefPtr<DisplayItemData> data =
    4807         170 :     new (aItem->Frame()->PresContext()) DisplayItemData(lmd, aItem->GetPerFrameKey(), aLayer);
    4808             : 
    4809          85 :   data->BeginUpdate(aLayer, aState, mContainerLayerGeneration, aItem);
    4810             : 
    4811          85 :   lmd->mDisplayItems.PutEntry(data);
    4812          85 :   return data;
    4813             : }
    4814             : 
    4815             : void
    4816          26 : FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame,
    4817             :                                      uint32_t aDisplayItemKey,
    4818             :                                      Layer* aLayer,
    4819             :                                      LayerState aState)
    4820             : {
    4821          26 :   DisplayItemData* oldData = GetDisplayItemData(aFrame, aDisplayItemKey);
    4822          26 :   if (oldData && oldData->mFrameList.Length() == 1) {
    4823          24 :     oldData->BeginUpdate(aLayer, aState, mContainerLayerGeneration);
    4824          24 :     return;
    4825             :   }
    4826             : 
    4827             :   LayerManagerData* lmd = static_cast<LayerManagerData*>
    4828           2 :     (mRetainingManager->GetUserData(&gLayerManagerUserData));
    4829             : 
    4830             :   RefPtr<DisplayItemData> data =
    4831           4 :     new (aFrame->PresContext()) DisplayItemData(lmd, aDisplayItemKey, aLayer, aFrame);
    4832             : 
    4833           2 :   data->BeginUpdate(aLayer, aState, mContainerLayerGeneration);
    4834             : 
    4835           2 :   lmd->mDisplayItems.PutEntry(data);
    4836             : }
    4837             : 
    4838        1298 : FrameLayerBuilder::ClippedDisplayItem::ClippedDisplayItem(nsDisplayItem* aItem,
    4839        1298 :                                                           uint32_t aGeneration)
    4840             :   : mItem(aItem)
    4841        1298 :   , mContainerLayerGeneration(aGeneration)
    4842             : {
    4843        1298 : }
    4844             : 
    4845        5192 : FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem()
    4846             : {
    4847        2596 :   if (mInactiveLayerManager) {
    4848         143 :     mInactiveLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
    4849             :   }
    4850        2596 : }
    4851             : 
    4852         259 : FrameLayerBuilder::PaintedLayerItemsEntry::PaintedLayerItemsEntry(const PaintedLayer *aKey)
    4853             :   : nsPtrHashKey<PaintedLayer>(aKey)
    4854             :   , mContainerLayerFrame(nullptr)
    4855             :   , mLastCommonClipCount(0)
    4856             :   , mContainerLayerGeneration(0)
    4857             :   , mHasExplicitLastPaintOffset(false)
    4858         259 :   , mCommonClipCount(0)
    4859             : {
    4860         259 : }
    4861             : 
    4862           0 : FrameLayerBuilder::PaintedLayerItemsEntry::PaintedLayerItemsEntry(const PaintedLayerItemsEntry& aOther)
    4863           0 :   : nsPtrHashKey<PaintedLayer>(aOther.mKey)
    4864           0 :   , mItems(aOther.mItems)
    4865             : {
    4866           0 :   NS_ERROR("Should never be called, since we ALLOW_MEMMOVE");
    4867           0 : }
    4868             : 
    4869         259 : FrameLayerBuilder::PaintedLayerItemsEntry::~PaintedLayerItemsEntry()
    4870             : {
    4871         259 : }
    4872             : 
    4873             : void
    4874        1374 : FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
    4875             :                                        nsDisplayItem* aItem,
    4876             :                                        LayerState aLayerState,
    4877             :                                        BasicLayerManager* aManager)
    4878             : {
    4879        1374 :   if (aLayer->Manager() != mRetainingManager)
    4880          82 :     return;
    4881             : 
    4882        1292 :   DisplayItemData *data = StoreDataForFrame(aItem, aLayer, aLayerState);
    4883        1292 :   data->mInactiveManager = aManager;
    4884             : }
    4885             : 
    4886             : nsIntPoint
    4887         151 : FrameLayerBuilder::GetLastPaintOffset(PaintedLayer* aLayer)
    4888             : {
    4889         151 :   PaintedLayerItemsEntry* entry = mPaintedLayerItems.PutEntry(aLayer);
    4890         151 :   if (entry) {
    4891         151 :     if (entry->mContainerLayerGeneration == 0) {
    4892           3 :       entry->mContainerLayerGeneration = mContainerLayerGeneration;
    4893             :     }
    4894         151 :     if (entry->mHasExplicitLastPaintOffset)
    4895         148 :       return entry->mLastPaintOffset;
    4896             :   }
    4897           3 :   return GetTranslationForPaintedLayer(aLayer);
    4898             : }
    4899             : 
    4900             : void
    4901         258 : FrameLayerBuilder::SavePreviousDataForLayer(PaintedLayer* aLayer, uint32_t aClipCount)
    4902             : {
    4903         258 :   PaintedLayerItemsEntry* entry = mPaintedLayerItems.PutEntry(aLayer);
    4904         258 :   if (entry) {
    4905         258 :     if (entry->mContainerLayerGeneration == 0) {
    4906         258 :       entry->mContainerLayerGeneration = mContainerLayerGeneration;
    4907             :     }
    4908         258 :     entry->mLastPaintOffset = GetTranslationForPaintedLayer(aLayer);
    4909         258 :     entry->mHasExplicitLastPaintOffset = true;
    4910         258 :     entry->mLastCommonClipCount = aClipCount;
    4911             :   }
    4912         258 : }
    4913             : 
    4914             : bool
    4915          11 : FrameLayerBuilder::CheckInLayerTreeCompressionMode()
    4916             : {
    4917          11 :   if (mInLayerTreeCompressionMode) {
    4918           0 :     return true;
    4919             :   }
    4920             : 
    4921             :   // If we wanted to be in layer tree compression mode, but weren't, then scheduled
    4922             :   // a delayed repaint where we will be.
    4923          11 :   mRootPresContext->PresShell()->GetRootFrame()->SchedulePaint(nsIFrame::PAINT_DELAYED_COMPRESS);
    4924             : 
    4925          11 :   return false;
    4926             : }
    4927             : 
    4928             : void
    4929         239 : ContainerState::CollectOldLayers()
    4930             : {
    4931         491 :   for (Layer* layer = mContainerLayer->GetFirstChild(); layer;
    4932             :        layer = layer->GetNextSibling()) {
    4933         252 :     NS_ASSERTION(!layer->HasUserData(&gMaskLayerUserData),
    4934             :                  "Mask layers should not be part of the layer tree.");
    4935         252 :     if (layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
    4936         199 :       NS_ASSERTION(layer->AsPaintedLayer(), "Wrong layer type");
    4937         199 :       mPaintedLayersAvailableForRecycling.PutEntry(static_cast<PaintedLayer*>(layer));
    4938             :     }
    4939             : 
    4940         252 :     if (Layer* maskLayer = layer->GetMaskLayer()) {
    4941           0 :       NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
    4942             :                    "Could not recycle mask layer, unsupported layer type.");
    4943           0 :       mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Nothing()), static_cast<ImageLayer*>(maskLayer));
    4944             :     }
    4945         252 :     for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
    4946           0 :       Layer* maskLayer = layer->GetAncestorMaskLayerAt(i);
    4947             : 
    4948           0 :       NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
    4949             :                    "Could not recycle mask layer, unsupported layer type.");
    4950           0 :       mRecycledMaskImageLayers.Put(MaskLayerKey(layer, Some(i)), static_cast<ImageLayer*>(maskLayer));
    4951             :     }
    4952             :   }
    4953         239 : }
    4954             : 
    4955          78 : struct OpaqueRegionEntry {
    4956             :   AnimatedGeometryRoot* mAnimatedGeometryRoot;
    4957             :   const ActiveScrolledRoot* mASR;
    4958             :   nsIntRegion mOpaqueRegion;
    4959             : };
    4960             : 
    4961             : static OpaqueRegionEntry*
    4962         128 : FindOpaqueRegionEntry(nsTArray<OpaqueRegionEntry>& aEntries,
    4963             :                       AnimatedGeometryRoot* aAnimatedGeometryRoot,
    4964             :                       const ActiveScrolledRoot* aASR)
    4965             : {
    4966         132 :   for (uint32_t i = 0; i < aEntries.Length(); ++i) {
    4967           7 :     OpaqueRegionEntry* d = &aEntries[i];
    4968          10 :     if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot &&
    4969           3 :         d->mASR == aASR) {
    4970           3 :       return d;
    4971             :     }
    4972             :   }
    4973         125 :   return nullptr;
    4974             : }
    4975             : 
    4976             : const ActiveScrolledRoot*
    4977           0 : FindDirectChildASR(const ActiveScrolledRoot* aParent, const ActiveScrolledRoot* aDescendant)
    4978             : {
    4979           0 :   MOZ_ASSERT(aDescendant, "can't start at the root when looking for a child");
    4980           0 :   MOZ_ASSERT(ActiveScrolledRoot::IsAncestor(aParent, aDescendant));
    4981           0 :   const ActiveScrolledRoot* directChild = aDescendant;
    4982           0 :   while (directChild->mParent != aParent) {
    4983           0 :     directChild = directChild->mParent;
    4984           0 :     MOZ_RELEASE_ASSERT(directChild, "this must not be null");
    4985             :   }
    4986           0 :   return directChild;
    4987             : }
    4988             : 
    4989             : static FrameMetrics::ViewID
    4990           0 : ViewIDForASR(const ActiveScrolledRoot* aASR)
    4991             : {
    4992           0 :   nsIContent* content = aASR->mScrollableFrame->GetScrolledFrame()->GetContent();
    4993           0 :   return nsLayoutUtils::FindOrCreateIDFor(content);
    4994             : }
    4995             : 
    4996             : static void
    4997         128 : FixUpFixedPositionLayer(Layer* aLayer,
    4998             :                         const ActiveScrolledRoot* aTargetASR,
    4999             :                         const ActiveScrolledRoot* aLeafScrollMetadataASR,
    5000             :                         const ActiveScrolledRoot* aContainerScrollMetadataASR,
    5001             :                         const ActiveScrolledRoot* aContainerCompositorASR,
    5002             :                         bool aIsFixedToRootScrollFrame)
    5003             : {
    5004         128 :   if (!aLayer->GetIsFixedPosition()) {
    5005         128 :     return;
    5006             :   }
    5007             : 
    5008             :   // Analyze ASRs to figure out if we need to fix up fixedness annotations on
    5009             :   // the layer. Fixed annotations are required in multiple cases:
    5010             :   //  - Sometimes we set scroll metadata on a layer for a scroll frame that we
    5011             :   //    don't want the layer to be moved by. (We have to do this if there is a
    5012             :   //    scrolled clip that is moved by that scroll frame.) So we set the fixed
    5013             :   //    annotation so that the compositor knows that it should ignore that
    5014             :   //    scroll metadata when determining the layer's position.
    5015             :   //  - Sometimes there is a scroll meta data on aLayer's parent layer for a
    5016             :   //    scroll frame that we don't want aLayer to be moved by. The most common
    5017             :   //    way for this to happen is with containerful root scrolling, where the
    5018             :   //    scroll metadata for the root scroll frame is on a container layer that
    5019             :   //    wraps the whole document's contents.
    5020             :   //  - Sometimes it's just needed for hit testing, i.e. figuring out what
    5021             :   //    scroll frame should be scrolled by events over the layer.
    5022             :   // A fixed layer needs to be annotated with the scroll ID of the scroll frame
    5023             :   // that it is *fixed with respect to*, i.e. the outermost scroll frame which
    5024             :   // does not move the layer. nsDisplayFixedPosition only ever annotates layers
    5025             :   // with the scroll ID of the presshell's root scroll frame, which is
    5026             :   // sometimes the wrong thing to do, so we correct it here. Specifically,
    5027             :   // it's the wrong thing to do if the fixed frame's containing block is a
    5028             :   // transformed frame - in that case, the fixed frame needs to scroll along
    5029             :   // with the transformed frame instead of being fixed with respect to the rsf.
    5030             :   // (It would be nice to compute the annotation only in one place and get it
    5031             :   // right, instead of fixing it up after the fact like this, but this will
    5032             :   // need to do for now.)
    5033             :   // compositorASR is the ASR that the layer would move with on the compositor
    5034             :   // if there were no fixed annotation on it.
    5035             :   const ActiveScrolledRoot* compositorASR =
    5036             :     aLeafScrollMetadataASR == aContainerScrollMetadataASR
    5037           0 :       ? aContainerCompositorASR
    5038           0 :       : aLeafScrollMetadataASR;
    5039             : 
    5040             :   // The goal of the annotation is to have the layer move with aTargetASR.
    5041           0 :   if (compositorASR && aTargetASR != compositorASR) {
    5042             :     // Mark this layer as fixed with respect to the child scroll frame of aTargetASR.
    5043           0 :     aLayer->SetFixedPositionData(
    5044             :       ViewIDForASR(FindDirectChildASR(aTargetASR, compositorASR)),
    5045           0 :       aLayer->GetFixedPositionAnchor(),
    5046           0 :       aLayer->GetFixedPositionSides());
    5047             :   } else {
    5048             :     // Remove the fixed annotation from the layer, unless this layers is fixed
    5049             :     // to the document's root scroll frame - in that case, the annotation is
    5050             :     // needed for hit testing, because fixed layers in iframes should scroll
    5051             :     // the iframe, even though their position is not affected by scrolling in
    5052             :     // the iframe. (The APZ hit testing code has a special case for this.)
    5053             :     // nsDisplayFixedPosition has annotated this layer with the document's
    5054             :     // root scroll frame's scroll id.
    5055           0 :     aLayer->SetIsFixedPosition(aIsFixedToRootScrollFrame);
    5056             :   }
    5057             : }
    5058             : 
    5059             : void
    5060         128 : ContainerState::SetupScrollingMetadata(NewLayerEntry* aEntry)
    5061             : {
    5062         128 :   if (mFlattenToSingleLayer) {
    5063             :     // animated geometry roots are forced to all match, so we can't
    5064             :     // use them and we don't get async scrolling.
    5065           0 :     return;
    5066             :   }
    5067             : 
    5068         128 :   if (!mBuilder->IsPaintingToWindow()) {
    5069             :     // async scrolling not possible, and async scrolling info not computed
    5070             :     // for this paint.
    5071           0 :     return;
    5072             :   }
    5073             : 
    5074         128 :   const ActiveScrolledRoot* startASR = aEntry->mScrollMetadataASR;
    5075         128 :   const ActiveScrolledRoot* stopASR = mContainerScrollMetadataASR;
    5076         128 :   if (!ActiveScrolledRoot::IsAncestor(stopASR, startASR)) {
    5077           0 :     if (ActiveScrolledRoot::IsAncestor(startASR, stopASR)) {
    5078             :       // startASR and stopASR are in the same branch of the ASR tree, but
    5079             :       // startASR is closer to the root. Just start at stopASR so that the loop
    5080             :       // below doesn't actually do anything.
    5081           0 :       startASR = stopASR;
    5082             :     } else {
    5083             :       // startASR and stopASR are in different branches of the
    5084             :       // ASR tree. Find a common ancestor and make that the stopASR.
    5085             :       // This can happen when there's a scrollable frame inside a fixed layer
    5086             :       // which has a scrolled clip. As far as scroll metadata is concerned,
    5087             :       // the scroll frame's scroll metadata will be a child of the scroll ID
    5088             :       // that scrolls the clip on the fixed layer. But as far as ASRs are
    5089             :       // concerned, those two ASRs are siblings, parented to the ASR of the
    5090             :       // fixed layer.
    5091           0 :       do {
    5092           0 :         stopASR = stopASR->mParent;
    5093           0 :       } while (!ActiveScrolledRoot::IsAncestor(stopASR, startASR));
    5094             :     }
    5095             :   }
    5096             : 
    5097         128 :   FixUpFixedPositionLayer(aEntry->mLayer, aEntry->mASR, startASR,
    5098             :                           mContainerScrollMetadataASR, mContainerCompositorASR,
    5099         256 :                           aEntry->mIsFixedToRootScrollFrame);
    5100             : 
    5101         256 :   AutoTArray<ScrollMetadata,2> metricsArray;
    5102         128 :   if (aEntry->mBaseScrollMetadata) {
    5103           0 :     metricsArray.AppendElement(*aEntry->mBaseScrollMetadata);
    5104             : 
    5105             :     // The base FrameMetrics was not computed by the nsIScrollableframe, so it
    5106             :     // should not have a mask layer.
    5107           0 :     MOZ_ASSERT(!aEntry->mBaseScrollMetadata->HasMaskLayer());
    5108             :   }
    5109             : 
    5110             :   // Any extra mask layers we need to attach to ScrollMetadatas.
    5111             :   // The list may already contain an entry added for the layer's scrolled clip
    5112             :   // so add to it rather than overwriting it (we clear the list when recycling
    5113             :   // a layer).
    5114         256 :   nsTArray<RefPtr<Layer>> maskLayers(aEntry->mLayer->GetAllAncestorMaskLayers());
    5115             : 
    5116             :   // Iterate over the ASR chain and create the corresponding scroll metadatas.
    5117             :   // This loop is slightly tricky because the scrollframe-to-clip relationship
    5118             :   // is reversed between DisplayItemClipChain and ScrollMetadata:
    5119             :   //  - DisplayItemClipChain associates the clip with the scroll frame that
    5120             :   //    this clip is *moved by*, i.e. the clip is moving inside the scroll
    5121             :   //    frame.
    5122             :   //  - ScrollMetaData associates the scroll frame with the clip that's
    5123             :   //    *just outside* the scroll frame, i.e. not moved by the scroll frame
    5124             :   //    itself.
    5125             :   // This discrepancy means that the leaf clip item of the clip chain is never
    5126             :   // applied to any scroll meta data. Instead, it was applied earlier as the
    5127             :   // layer's clip (or fused with the painted layer contents), or it was applied
    5128             :   // as a ScrolledClip on the layer.
    5129         128 :   const DisplayItemClipChain* clipChain = aEntry->mClipChain;
    5130             : 
    5131         131 :   for (const ActiveScrolledRoot* asr = startASR; asr != stopASR; asr = asr->mParent) {
    5132           3 :     if (!asr) {
    5133           0 :       MOZ_ASSERT_UNREACHABLE("Should have encountered stopASR on the way up.");
    5134             :       break;
    5135             :     }
    5136           3 :     if (clipChain && clipChain->mASR == asr) {
    5137           0 :       clipChain = clipChain->mParent;
    5138             :     }
    5139             : 
    5140           3 :     nsIScrollableFrame* scrollFrame = asr->mScrollableFrame;
    5141             :     const DisplayItemClip* clip =
    5142           3 :       (clipChain && clipChain->mASR == asr->mParent) ? &clipChain->mClip : nullptr;
    5143             : 
    5144             :     Maybe<ScrollMetadata> metadata =
    5145             :       scrollFrame->ComputeScrollMetadata(aEntry->mLayer, mContainerReferenceFrame,
    5146           6 :                                          mParameters, clip);
    5147           3 :     if (!metadata) {
    5148           0 :       continue;
    5149             :     }
    5150             : 
    5151           6 :     if (clip &&
    5152           6 :         clip->HasClip() &&
    5153           3 :         clip->GetRoundedRectCount() > 0)
    5154             :     {
    5155             :       // The clip in between this scrollframe and its ancestor scrollframe
    5156             :       // requires a mask layer. Since this mask layer should not move with
    5157             :       // the APZC associated with this FrameMetrics, we attach the mask
    5158             :       // layer as an additional, separate clip.
    5159           0 :       Maybe<size_t> nextIndex = Some(maskLayers.Length());
    5160             :       RefPtr<Layer> maskLayer =
    5161           0 :         CreateMaskLayer(aEntry->mLayer, *clip, nextIndex, clip->GetRoundedRectCount());
    5162           0 :       if (maskLayer) {
    5163           0 :         MOZ_ASSERT(metadata->HasScrollClip());
    5164           0 :         metadata->ScrollClip().SetMaskLayerIndex(nextIndex);
    5165           0 :         maskLayers.AppendElement(maskLayer);
    5166             :       }
    5167             :     }
    5168             : 
    5169           3 :     metricsArray.AppendElement(*metadata);
    5170             :   }
    5171             : 
    5172             :   // Watch out for FrameMetrics copies in profiles
    5173         128 :   aEntry->mLayer->SetScrollMetadata(metricsArray);
    5174         128 :   aEntry->mLayer->SetAncestorMaskLayers(maskLayers);
    5175             : }
    5176             : 
    5177             : static inline Maybe<ParentLayerIntRect>
    5178         126 : GetStationaryClipInContainer(Layer* aLayer)
    5179             : {
    5180         126 :   if (size_t metricsCount = aLayer->GetScrollMetadataCount()) {
    5181           3 :     return aLayer->GetScrollMetadata(metricsCount - 1).GetClipRect();
    5182             :   }
    5183         123 :   return aLayer->GetClipRect();
    5184             : }
    5185             : 
    5186             : void
    5187          54 : ContainerState::PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer)
    5188             : {
    5189         108 :   AutoTArray<OpaqueRegionEntry,4> opaqueRegions;
    5190          54 :   bool hideAll = false;
    5191          54 :   int32_t opaqueRegionForContainer = -1;
    5192             : 
    5193         252 :   for (int32_t i = mNewChildLayers.Length() - 1; i >= 0; --i) {
    5194         198 :     NewLayerEntry* e = &mNewChildLayers.ElementAt(i);
    5195         198 :     if (!e->mLayer) {
    5196          70 :       continue;
    5197             :     }
    5198             : 
    5199         128 :     OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions, e->mAnimatedGeometryRoot, e->mASR);
    5200             : 
    5201         128 :     SetupScrollingMetadata(e);
    5202             : 
    5203         128 :     if (hideAll) {
    5204           2 :       e->mVisibleRegion.SetEmpty();
    5205         126 :     } else if (!e->mLayer->IsScrollbarContainer()) {
    5206         252 :       Maybe<ParentLayerIntRect> clipRect = GetStationaryClipInContainer(e->mLayer);
    5207         378 :       if (clipRect && opaqueRegionForContainer >= 0 &&
    5208         126 :           opaqueRegions[opaqueRegionForContainer].mOpaqueRegion.Contains(clipRect->ToUnknownRect())) {
    5209           0 :         e->mVisibleRegion.SetEmpty();
    5210         126 :       } else if (data) {
    5211           1 :         e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion);
    5212             :       }
    5213             :     }
    5214             : 
    5215         256 :     SetOuterVisibleRegionForLayer(e->mLayer,
    5216             :                                   e->mVisibleRegion,
    5217         128 :                                   e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr,
    5218         256 :                                   e->mUntransformedVisibleRegion);
    5219             : 
    5220         128 :     if (!e->mOpaqueRegion.IsEmpty()) {
    5221          39 :       AnimatedGeometryRoot* animatedGeometryRootToCover = e->mAnimatedGeometryRoot;
    5222          39 :       const ActiveScrolledRoot* asrToCover = e->mASR;
    5223          39 :       if (e->mOpaqueForAnimatedGeometryRootParent &&
    5224           0 :           e->mAnimatedGeometryRoot->mParentAGR == mContainerAnimatedGeometryRoot) {
    5225           0 :         animatedGeometryRootToCover = mContainerAnimatedGeometryRoot;
    5226           0 :         asrToCover = mContainerASR;
    5227           0 :         data = FindOpaqueRegionEntry(opaqueRegions, animatedGeometryRootToCover, asrToCover);
    5228             :       }
    5229             : 
    5230          39 :       if (!data) {
    5231          76 :         if (animatedGeometryRootToCover == mContainerAnimatedGeometryRoot &&
    5232          37 :             asrToCover == mContainerASR) {
    5233          37 :           NS_ASSERTION(opaqueRegionForContainer == -1, "Already found it?");
    5234          37 :           opaqueRegionForContainer = opaqueRegions.Length();
    5235             :         }
    5236          39 :         data = opaqueRegions.AppendElement();
    5237          39 :         data->mAnimatedGeometryRoot = animatedGeometryRootToCover;
    5238          39 :         data->mASR = asrToCover;
    5239             :       }
    5240             : 
    5241          78 :       nsIntRegion clippedOpaque = e->mOpaqueRegion;
    5242          78 :       Maybe<ParentLayerIntRect> clipRect = e->mLayer->GetCombinedClipRect();
    5243          39 :       if (clipRect) {
    5244           2 :         clippedOpaque.AndWith(clipRect->ToUnknownRect());
    5245             :       }
    5246          39 :       if (e->mLayer->GetScrolledClip()) {
    5247             :         // The clip can move asynchronously, so we can't rely on opaque parts
    5248             :         // staying visible.
    5249           0 :         clippedOpaque.SetEmpty();
    5250          39 :       } else if (e->mHideAllLayersBelow) {
    5251          26 :         hideAll = true;
    5252             :       }
    5253          39 :       data->mOpaqueRegion.Or(data->mOpaqueRegion, clippedOpaque);
    5254             :     }
    5255             : 
    5256         128 :     if (e->mLayer->GetType() == Layer::TYPE_READBACK) {
    5257             :       // ReadbackLayers need to accurately read what's behind them. So,
    5258             :       // we don't want to do any occlusion culling of layers behind them.
    5259             :       // Theoretically we could just punch out the ReadbackLayer's rectangle
    5260             :       // from all mOpaqueRegions, but that's probably not worth doing.
    5261           0 :       opaqueRegions.Clear();
    5262           0 :       opaqueRegionForContainer = -1;
    5263             :     }
    5264             :   }
    5265             : 
    5266          54 :   if (opaqueRegionForContainer >= 0) {
    5267             :     aOpaqueRegionForContainer->Or(*aOpaqueRegionForContainer,
    5268          37 :         opaqueRegions[opaqueRegionForContainer].mOpaqueRegion);
    5269             :   }
    5270          54 : }
    5271             : 
    5272             : void
    5273         239 : ContainerState::Finish(uint32_t* aTextContentFlags,
    5274             :                        const nsIntRect& aContainerPixelBounds,
    5275             :                        nsDisplayList* aChildItems, bool* aHasComponentAlphaChildren)
    5276             : {
    5277         239 :   mPaintedLayerDataTree.Finish();
    5278             : 
    5279         239 :   if (!mParameters.mForEventsAndPluginsOnly && !gfxPrefs::LayoutUseContainersForRootFrames()) {
    5280             :     // Bug 1336544 tracks re-enabling this assertion in the
    5281             :     // gfxPrefs::LayoutUseContainersForRootFrames() case.
    5282         167 :     NS_ASSERTION(mContainerBounds.IsEqualInterior(mAccumulatedChildBounds),
    5283             :                  "Bounds computation mismatch");
    5284             :   }
    5285             : 
    5286         239 :   if (mLayerBuilder->IsBuildingRetainedLayers()) {
    5287         108 :     nsIntRegion containerOpaqueRegion;
    5288          54 :     PostprocessRetainedLayers(&containerOpaqueRegion);
    5289          54 :     if (containerOpaqueRegion.Contains(aContainerPixelBounds)) {
    5290          26 :       aChildItems->SetIsOpaque();
    5291             :     }
    5292             :   }
    5293             : 
    5294         239 :   uint32_t textContentFlags = 0;
    5295             : 
    5296             :   // Make sure that current/existing layers are added to the parent and are
    5297             :   // in the correct order.
    5298         239 :   Layer* layer = nullptr;
    5299         239 :   Layer* prevChild = nullptr;
    5300         831 :   for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i, prevChild = layer) {
    5301         592 :     if (!mNewChildLayers[i].mLayer) {
    5302         255 :       continue;
    5303             :     }
    5304             : 
    5305         337 :     layer = mNewChildLayers[i].mLayer;
    5306             : 
    5307         337 :     if (!layer->GetVisibleRegion().IsEmpty()) {
    5308         230 :       textContentFlags |=
    5309         230 :         layer->GetContentFlags() & (Layer::CONTENT_COMPONENT_ALPHA |
    5310             :                                     Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT |
    5311             :                                     Layer::CONTENT_DISABLE_FLATTENING);
    5312             : 
    5313             :       // Notify the parent of component alpha children unless it's coming from
    5314             :       // within a child that has asked not to contribute to layer flattening.
    5315         230 :       if (aHasComponentAlphaChildren &&
    5316         230 :           mNewChildLayers[i].mPropagateComponentAlphaFlattening &&
    5317           0 :           (layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA)) {
    5318             : 
    5319           0 :         for (int32_t j = i - 1; j >= 0; j--) {
    5320           0 :           if (mNewChildLayers[j].mVisibleRegion.Intersects(mNewChildLayers[i].mVisibleRegion.GetBounds())) {
    5321           0 :             if (mNewChildLayers[j].mLayerState != LAYER_ACTIVE_FORCE) {
    5322           0 :               *aHasComponentAlphaChildren = true;
    5323             :             }
    5324           0 :             break;
    5325             : 
    5326             :           }
    5327             : 
    5328             :         }
    5329             :       }
    5330             :     }
    5331             : 
    5332         337 :     if (!layer->GetParent()) {
    5333             :       // This is not currently a child of the container, so just add it
    5334             :       // now.
    5335         174 :       mContainerLayer->InsertAfter(layer, prevChild);
    5336             :     } else {
    5337         163 :       NS_ASSERTION(layer->GetParent() == mContainerLayer,
    5338             :                    "Layer shouldn't be the child of some other container");
    5339         163 :       if (layer->GetPrevSibling() != prevChild) {
    5340           0 :         mContainerLayer->RepositionChild(layer, prevChild);
    5341             :       }
    5342             :     }
    5343             :   }
    5344             : 
    5345             :   // Remove old layers that have become unused.
    5346         239 :   if (!layer) {
    5347           0 :     layer = mContainerLayer->GetFirstChild();
    5348             :   } else {
    5349         239 :     layer = layer->GetNextSibling();
    5350             :   }
    5351         417 :   while (layer) {
    5352          89 :     Layer *layerToRemove = layer;
    5353          89 :     layer = layer->GetNextSibling();
    5354          89 :     mContainerLayer->RemoveChild(layerToRemove);
    5355             :   }
    5356             : 
    5357         239 :   *aTextContentFlags = textContentFlags;
    5358         239 : }
    5359             : 
    5360         239 : static inline gfxSize RoundToFloatPrecision(const gfxSize& aSize)
    5361             : {
    5362         239 :   return gfxSize(float(aSize.width), float(aSize.height));
    5363             : }
    5364             : 
    5365          24 : static void RestrictScaleToMaxLayerSize(gfxSize& aScale,
    5366             :                                         const nsRect& aVisibleRect,
    5367             :                                         nsIFrame* aContainerFrame,
    5368             :                                         Layer* aContainerLayer)
    5369             : {
    5370          24 :   if (!aContainerLayer->Manager()->IsWidgetLayerManager()) {
    5371          24 :     return;
    5372             :   }
    5373             : 
    5374             :   nsIntRect pixelSize =
    5375           0 :     aVisibleRect.ScaleToOutsidePixels(aScale.width, aScale.height,
    5376           0 :                                       aContainerFrame->PresContext()->AppUnitsPerDevPixel());
    5377             : 
    5378           0 :   int32_t maxLayerSize = aContainerLayer->GetMaxLayerSize();
    5379             : 
    5380           0 :   if (pixelSize.width > maxLayerSize) {
    5381           0 :     float scale = (float)pixelSize.width / maxLayerSize;
    5382           0 :     scale = gfxUtils::ClampToScaleFactor(scale);
    5383           0 :     aScale.width /= scale;
    5384             :   }
    5385           0 :   if (pixelSize.height > maxLayerSize) {
    5386           0 :     float scale = (float)pixelSize.height / maxLayerSize;
    5387           0 :     scale = gfxUtils::ClampToScaleFactor(scale);
    5388           0 :     aScale.height /= scale;
    5389             :   }
    5390             : }
    5391             : static bool
    5392         239 : ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
    5393             :                            nsDisplayListBuilder* aDisplayListBuilder,
    5394             :                            nsIFrame* aContainerFrame,
    5395             :                            nsDisplayItem* aContainerItem,
    5396             :                            const nsRect& aVisibleRect,
    5397             :                            const Matrix4x4* aTransform,
    5398             :                            const ContainerLayerParameters& aIncomingScale,
    5399             :                            ContainerLayer* aLayer,
    5400             :                            LayerState aState,
    5401             :                            ContainerLayerParameters& aOutgoingScale)
    5402             : {
    5403         239 :   nsIntPoint offset;
    5404             : 
    5405             :   Matrix4x4 transform =
    5406         239 :     Matrix4x4::Scaling(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
    5407         239 :   if (aTransform) {
    5408             :     // aTransform is applied first, then the scale is applied to the result
    5409          24 :     transform = (*aTransform)*transform;
    5410             :     // Set any matrix entries close to integers to be those exact integers.
    5411             :     // This protects against floating-point inaccuracies causing problems
    5412             :     // in the checks below.
    5413             :     // We use the fixed epsilon version here because we don't want the nudging
    5414             :     // to depend on the scroll position.
    5415          24 :     transform.NudgeToIntegersFixedEpsilon();
    5416             :   }
    5417         239 :   Matrix transform2d;
    5418         478 :   if (aContainerFrame &&
    5419         470 :       (aState == LAYER_INACTIVE || aState == LAYER_SVG_EFFECTS) &&
    5420          48 :       (!aTransform || (aTransform->Is2D(&transform2d) &&
    5421          24 :                        !transform2d.HasNonTranslation()))) {
    5422             :     // When we have an inactive ContainerLayer, translate the container by the offset to the
    5423             :     // reference frame (and offset all child layers by the reverse) so that the coordinate
    5424             :     // space of the child layers isn't affected by scrolling.
    5425             :     // This gets confusing for complicated transform (since we'd have to compute the scale
    5426             :     // factors for the matrix), so we don't bother. Any frames that are building an nsDisplayTransform
    5427             :     // for a css transform would have 0,0 as their offset to the reference frame, so this doesn't
    5428             :     // matter.
    5429         152 :     nsPoint appUnitOffset = aDisplayListBuilder->ToReferenceFrame(aContainerFrame);
    5430         152 :     nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
    5431         304 :     offset = nsIntPoint(
    5432         152 :         NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.x, appUnitsPerDevPixel)*aIncomingScale.mXScale),
    5433         152 :         NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.y, appUnitsPerDevPixel)*aIncomingScale.mYScale));
    5434             :   }
    5435         239 :   transform.PostTranslate(offset.x + aIncomingScale.mOffset.x,
    5436         239 :                           offset.y + aIncomingScale.mOffset.y,
    5437         478 :                           0);
    5438             : 
    5439         239 :   if (transform.IsSingular()) {
    5440           0 :     return false;
    5441             :   }
    5442             : 
    5443         239 :   bool canDraw2D = transform.CanDraw2D(&transform2d);
    5444         239 :   gfxSize scale;
    5445             :   // XXX Should we do something for 3D transforms?
    5446         478 :   if (canDraw2D &&
    5447         478 :       !aContainerFrame->Combines3DTransformWithAncestors() &&
    5448         239 :       !aContainerFrame->HasPerspective()) {
    5449             :     // If the container's transform is animated off main thread, fix a suitable scale size
    5450             :     // for animation
    5451         434 :     if (aContainerItem &&
    5452         263 :         aContainerItem->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
    5453          24 :         EffectCompositor::HasAnimationsForCompositor(
    5454             :           aContainerFrame, eCSSProperty_transform)) {
    5455             :       // Use the size of the nearest widget as the maximum size.  This
    5456             :       // is important since it might be a popup that is bigger than the
    5457             :       // pres context's size.
    5458           0 :       nsPresContext* presContext = aContainerFrame->PresContext();
    5459           0 :       nsIWidget* widget = aContainerFrame->GetNearestWidget();
    5460           0 :       nsSize displaySize;
    5461           0 :       if (widget) {
    5462           0 :         LayoutDeviceIntSize widgetSize = widget->GetClientSize();
    5463           0 :         int32_t p2a = presContext->AppUnitsPerDevPixel();
    5464           0 :         displaySize.width = NSIntPixelsToAppUnits(widgetSize.width, p2a);
    5465           0 :         displaySize.height = NSIntPixelsToAppUnits(widgetSize.height, p2a);
    5466             :       } else {
    5467           0 :         displaySize = presContext->GetVisibleArea().Size();
    5468             :       }
    5469             :       // compute scale using the animation on the container (ignoring
    5470             :       // its ancestors)
    5471             :       scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(
    5472           0 :                 aContainerFrame, aVisibleRect.Size(),
    5473           0 :                 displaySize);
    5474             :       // multiply by the scale inherited from ancestors--we use a uniform
    5475             :       // scale factor to prevent blurring when the layer is rotated.
    5476           0 :       float incomingScale = std::max(aIncomingScale.mXScale, aIncomingScale.mYScale);
    5477           0 :       scale.width *= incomingScale;
    5478           0 :       scale.height *= incomingScale;
    5479             :     } else {
    5480             :       // Scale factors are normalized to a power of 2 to reduce the number of resolution changes
    5481         239 :       scale = RoundToFloatPrecision(ThebesMatrix(transform2d).ScaleFactors(true));
    5482             :       // For frames with a changing transform that's not just a translation,
    5483             :       // round scale factors up to nearest power-of-2 boundary so that we don't
    5484             :       // keep having to redraw the content as it scales up and down. Rounding up to nearest
    5485             :       // power-of-2 boundary ensures we never scale up, only down --- avoiding
    5486             :       // jaggies. It also ensures we never scale down by more than a factor of 2,
    5487             :       // avoiding bad downscaling quality.
    5488         239 :       Matrix frameTransform;
    5489         478 :       if (ActiveLayerTracker::IsStyleAnimated(aDisplayListBuilder, aContainerFrame, eCSSProperty_transform) &&
    5490         239 :           aTransform &&
    5491           0 :           (!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) {
    5492             :         // Don't clamp the scale factor when the new desired scale factor matches the old one
    5493             :         // or it was previously unscaled.
    5494           0 :         bool clamp = true;
    5495           0 :         Matrix oldFrameTransform2d;
    5496           0 :         if (aLayer->GetBaseTransform().Is2D(&oldFrameTransform2d)) {
    5497           0 :           gfxSize oldScale = RoundToFloatPrecision(ThebesMatrix(oldFrameTransform2d).ScaleFactors(true));
    5498           0 :           if (oldScale == scale || oldScale == gfxSize(1.0, 1.0)) {
    5499           0 :             clamp = false;
    5500             :           }
    5501             :         }
    5502           0 :         if (clamp) {
    5503           0 :           scale.width = gfxUtils::ClampToScaleFactor(scale.width);
    5504           0 :           scale.height = gfxUtils::ClampToScaleFactor(scale.height);
    5505             :         }
    5506             :       } else {
    5507             :         // XXX Do we need to move nearly-integer values to integers here?
    5508             :       }
    5509             :     }
    5510             :     // If the scale factors are too small, just use 1.0. The content is being
    5511             :     // scaled out of sight anyway.
    5512         239 :     if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
    5513           0 :       scale = gfxSize(1.0, 1.0);
    5514             :     }
    5515             :     // If this is a transform container layer, then pre-rendering might
    5516             :     // mean we try render a layer bigger than the max texture size. If we have
    5517             :     // tiling, that's not a problem, since we'll automatically choose a tiled
    5518             :     // layer for layers of that size. If not, we need to apply clamping to
    5519             :     // prevent this.
    5520         239 :     if (aTransform && !gfxPrefs::LayersTilesEnabled()) {
    5521          24 :       RestrictScaleToMaxLayerSize(scale, aVisibleRect, aContainerFrame, aLayer);
    5522             :     }
    5523             :   } else {
    5524           0 :     scale = gfxSize(1.0, 1.0);
    5525             :   }
    5526             : 
    5527             :   // Store the inverse of our resolution-scale on the layer
    5528         239 :   aLayer->SetBaseTransform(transform);
    5529         239 :   aLayer->SetPreScale(1.0f/float(scale.width),
    5530         478 :                       1.0f/float(scale.height));
    5531         239 :   aLayer->SetInheritedScale(aIncomingScale.mXScale,
    5532         478 :                             aIncomingScale.mYScale);
    5533             : 
    5534             :   aOutgoingScale =
    5535         239 :     ContainerLayerParameters(scale.width, scale.height, -offset, aIncomingScale);
    5536         239 :   if (aTransform) {
    5537          24 :     aOutgoingScale.mInTransformedSubtree = true;
    5538          24 :     if (ActiveLayerTracker::IsStyleAnimated(aDisplayListBuilder, aContainerFrame,
    5539             :                                             eCSSProperty_transform)) {
    5540           0 :       aOutgoingScale.mInActiveTransformedSubtree = true;
    5541             :     }
    5542             :   }
    5543         532 :   if ((aLayerBuilder->IsBuildingRetainedLayers() &&
    5544         347 :        (!canDraw2D || transform2d.HasNonIntegerTranslation())) ||
    5545         478 :       aContainerFrame->Extend3DContext() ||
    5546         717 :       aContainerFrame->Combines3DTransformWithAncestors() ||
    5547             :       // For async transform animation, the value would be changed at
    5548             :       // any time, integer translation is not always true.
    5549         239 :       aContainerFrame->HasAnimationOfTransform()) {
    5550           0 :     aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true;
    5551             :   }
    5552         239 :   return true;
    5553             : }
    5554             : 
    5555             : already_AddRefed<ContainerLayer>
    5556         239 : FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
    5557             :                                           LayerManager* aManager,
    5558             :                                           nsIFrame* aContainerFrame,
    5559             :                                           nsDisplayItem* aContainerItem,
    5560             :                                           nsDisplayList* aChildren,
    5561             :                                           const ContainerLayerParameters& aParameters,
    5562             :                                           const Matrix4x4* aTransform,
    5563             :                                           uint32_t aFlags)
    5564             : {
    5565             :   uint32_t containerDisplayItemKey =
    5566         239 :     aContainerItem ? aContainerItem->GetPerFrameKey() : nsDisplayItem::TYPE_ZERO;
    5567         239 :   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
    5568         239 :   NS_ASSERTION(!aContainerItem ||
    5569             :                aContainerItem->Frame() == aContainerFrame,
    5570             :                "Container display item must match given frame");
    5571             : 
    5572         239 :   if (!aParameters.mXScale || !aParameters.mYScale) {
    5573           0 :     return nullptr;
    5574             :   }
    5575             : 
    5576         478 :   RefPtr<ContainerLayer> containerLayer;
    5577         239 :   if (aManager == mRetainingManager) {
    5578             :     // Using GetOldLayerFor will search merged frames, as well as the underlying
    5579             :     // frame. The underlying frame can change when a page scrolls, so this
    5580             :     // avoids layer recreation in the situation that a new underlying frame is
    5581             :     // picked for a layer.
    5582         195 :     Layer* oldLayer = nullptr;
    5583         195 :     if (aContainerItem) {
    5584         169 :       oldLayer = GetOldLayerFor(aContainerItem);
    5585             :     } else {
    5586          26 :       DisplayItemData *data = GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
    5587          26 :       if (data) {
    5588          24 :         oldLayer = data->mLayer;
    5589             :       }
    5590             :     }
    5591             : 
    5592         195 :     if (oldLayer) {
    5593         181 :       NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
    5594         181 :       if (oldLayer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
    5595             :         // The old layer for this item is actually our PaintedLayer
    5596             :         // because we rendered its layer into that PaintedLayer. So we
    5597             :         // don't actually have a retained container layer.
    5598             :       } else {
    5599         181 :         NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
    5600             :                      "Wrong layer type");
    5601         181 :         containerLayer = static_cast<ContainerLayer*>(oldLayer);
    5602         181 :         ResetLayerStateForRecycling(containerLayer);
    5603             :       }
    5604             :     }
    5605             :   }
    5606         239 :   if (!containerLayer) {
    5607             :     // No suitable existing layer was found.
    5608          58 :     containerLayer = aManager->CreateContainerLayer();
    5609          58 :     if (!containerLayer)
    5610           0 :       return nullptr;
    5611             :   }
    5612             : 
    5613         239 :   LayerState state = aContainerItem ? aContainerItem->GetLayerState(aBuilder, aManager, aParameters) : LAYER_ACTIVE;
    5614         399 :   if (state == LAYER_INACTIVE &&
    5615         160 :       nsDisplayItem::ForceActiveLayers()) {
    5616           0 :     state = LAYER_ACTIVE;
    5617             :   }
    5618             : 
    5619         239 :   if (aContainerItem && state == LAYER_ACTIVE_EMPTY) {
    5620             :     // Empty layers only have metadata and should never have display items. We
    5621             :     // early exit because later, invalidation will walk up the frame tree to
    5622             :     // determine which painted layer gets invalidated. Since an empty layer
    5623             :     // should never have anything to paint, it should never be invalidated.
    5624           0 :     NS_ASSERTION(aChildren->IsEmpty(), "Should have no children");
    5625           0 :     return containerLayer.forget();
    5626             :   }
    5627             : 
    5628         239 :   const ActiveScrolledRoot* containerASR = aContainerItem ? aContainerItem->GetActiveScrolledRoot() : nullptr;
    5629         239 :   const ActiveScrolledRoot* containerScrollMetadataASR = aParameters.mScrollMetadataASR;
    5630         239 :   const ActiveScrolledRoot* containerCompositorASR = aParameters.mCompositorASR;
    5631             : 
    5632         239 :   if (!aContainerItem && gfxPrefs::LayoutUseContainersForRootFrames()) {
    5633           0 :     containerASR = aBuilder->ActiveScrolledRootForRootScrollframe();
    5634           0 :     containerScrollMetadataASR = containerASR;
    5635           0 :     containerCompositorASR = containerASR;
    5636             :   }
    5637             : 
    5638         239 :   ContainerLayerParameters scaleParameters;
    5639         478 :   nsRect bounds = aChildren->GetClippedBoundsWithRespectToASR(aBuilder, containerASR);
    5640             :   nsRect childrenVisible =
    5641         195 :       aContainerItem ? aContainerItem->GetVisibleRectForChildren() :
    5642         673 :           aContainerFrame->GetVisualOverflowRectRelativeToSelf();
    5643         717 :   if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame,
    5644             :                                   aContainerItem,
    5645         478 :                                   bounds.Intersect(childrenVisible),
    5646             :                                   aTransform, aParameters,
    5647             :                                   containerLayer, state, scaleParameters)) {
    5648           0 :     return nullptr;
    5649             :   }
    5650             : 
    5651         239 :   uint32_t oldGeneration = mContainerLayerGeneration;
    5652         239 :   mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
    5653             : 
    5654         239 :   if (mRetainingManager) {
    5655         195 :     if (aContainerItem) {
    5656         169 :       StoreDataForFrame(aContainerItem, containerLayer, LAYER_ACTIVE);
    5657             :     } else {
    5658          26 :       StoreDataForFrame(aContainerFrame, containerDisplayItemKey, containerLayer, LAYER_ACTIVE);
    5659             :     }
    5660             :   }
    5661             : 
    5662             :   LayerManagerData* data = static_cast<LayerManagerData*>
    5663         239 :     (aManager->GetUserData(&gLayerManagerUserData));
    5664             : 
    5665         239 :   nsIntRect pixBounds;
    5666             :   nscoord appUnitsPerDevPixel;
    5667         239 :   bool flattenToSingleLayer = false;
    5668         478 :   if ((aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) &&
    5669           0 :       mRetainingManager &&
    5670         239 :       mRetainingManager->ShouldAvoidComponentAlphaLayers() &&
    5671           0 :       !nsLayoutUtils::AsyncPanZoomEnabled(aContainerFrame))
    5672             :   {
    5673           0 :     flattenToSingleLayer = true;
    5674             :   }
    5675             : 
    5676         239 :   nscolor backgroundColor = NS_RGBA(0,0,0,0);
    5677         239 :   if (aFlags & CONTAINER_ALLOW_PULL_BACKGROUND_COLOR) {
    5678         188 :     backgroundColor = aParameters.mBackgroundColor;
    5679             :   }
    5680             : 
    5681             :   uint32_t flags;
    5682             :   while (true) {
    5683             :     ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
    5684             :                          aContainerFrame, aContainerItem, bounds,
    5685             :                          containerLayer, scaleParameters, flattenToSingleLayer,
    5686             :                          backgroundColor, containerASR, containerScrollMetadataASR,
    5687         239 :                          containerCompositorASR);
    5688             : 
    5689         239 :     state.ProcessDisplayItems(aChildren);
    5690             : 
    5691             :     // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
    5692             :     // This is suboptimal ... a child could have text that's over transparent
    5693             :     // pixels in its own layer, but over opaque parts of previous siblings.
    5694         239 :     bool hasComponentAlphaChildren = false;
    5695             :     bool mayFlatten =
    5696         434 :       mRetainingManager &&
    5697         249 :       mRetainingManager->ShouldAvoidComponentAlphaLayers() &&
    5698         347 :       !flattenToSingleLayer &&
    5699         293 :       !nsLayoutUtils::AsyncPanZoomEnabled(aContainerFrame);
    5700             : 
    5701         239 :     pixBounds = state.ScaleToOutsidePixels(bounds, false);
    5702         239 :     appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
    5703         239 :     state.Finish(&flags, pixBounds, aChildren, mayFlatten ? &hasComponentAlphaChildren : nullptr);
    5704             : 
    5705         239 :     if (hasComponentAlphaChildren &&
    5706         239 :         !(flags & Layer::CONTENT_DISABLE_FLATTENING) &&
    5707           0 :         containerLayer->HasMultipleChildren())
    5708             :     {
    5709             :       // Since we don't want any component alpha layers on BasicLayers, we repeat
    5710             :       // the layer building process with this explicitely forced off.
    5711             :       // We restore the previous FrameLayerBuilder state since the first set
    5712             :       // of layer building will have changed it.
    5713           0 :       flattenToSingleLayer = true;
    5714             : 
    5715             :       // Restore DisplayItemData
    5716           0 :       for (auto iter = data->mDisplayItems.Iter(); !iter.Done(); iter.Next()) {
    5717           0 :         DisplayItemData* data = iter.Get()->GetKey();
    5718           0 :         if (data->mUsed && data->mContainerLayerGeneration >= mContainerLayerGeneration) {
    5719           0 :           iter.Remove();
    5720             :         }
    5721             :       }
    5722             : 
    5723             :       // Restore PaintedLayerItemEntries
    5724           0 :       for (auto iter = mPaintedLayerItems.Iter(); !iter.Done(); iter.Next()) {
    5725           0 :         PaintedLayerItemsEntry* entry = iter.Get();
    5726           0 :         if (entry->mContainerLayerGeneration >= mContainerLayerGeneration) {
    5727             :           // We can just remove these items rather than attempting to revert them
    5728             :           // because we're going to want to invalidate everything when transitioning
    5729             :           // to component alpha flattening.
    5730           0 :           iter.Remove();
    5731           0 :           continue;
    5732             :         }
    5733             : 
    5734           0 :         for (uint32_t i = 0; i < entry->mItems.Length(); i++) {
    5735           0 :           if (entry->mItems[i].mContainerLayerGeneration >= mContainerLayerGeneration) {
    5736           0 :             entry->mItems.TruncateLength(i);
    5737           0 :             break;
    5738             :           }
    5739             :         }
    5740             :       }
    5741             : 
    5742           0 :       aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
    5743           0 :       continue;
    5744             :     }
    5745         239 :     break;
    5746           0 :   }
    5747             : 
    5748             :   // CONTENT_COMPONENT_ALPHA is propogated up to the nearest CONTENT_OPAQUE
    5749             :   // ancestor so that BasicLayerManager knows when to copy the background into
    5750             :   // pushed groups. Accelerated layers managers can't necessarily do this (only
    5751             :   // when the visible region is a simple rect), so we propogate
    5752             :   // CONTENT_COMPONENT_ALPHA_DESCENDANT all the way to the root.
    5753         239 :   if (flags & Layer::CONTENT_COMPONENT_ALPHA) {
    5754           5 :     flags |= Layer::CONTENT_COMPONENT_ALPHA_DESCENDANT;
    5755             :   }
    5756             : 
    5757             :   // Make sure that rounding the visible region out didn't add any area
    5758             :   // we won't paint
    5759         239 :   if (aChildren->IsOpaque() && !aChildren->NeedsTransparentSurface()) {
    5760          28 :     bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
    5761          28 :     if (bounds.Contains(ToAppUnits(pixBounds, appUnitsPerDevPixel))) {
    5762             :       // Clear CONTENT_COMPONENT_ALPHA and add CONTENT_OPAQUE instead.
    5763          28 :       flags &= ~Layer::CONTENT_COMPONENT_ALPHA;
    5764          28 :       flags |= Layer::CONTENT_OPAQUE;
    5765             :     }
    5766             :   }
    5767         239 :   containerLayer->SetContentFlags(flags);
    5768             :   // If aContainerItem is non-null some BuildContainerLayer further up the
    5769             :   // call stack is responsible for setting containerLayer's visible region.
    5770         239 :   if (!aContainerItem) {
    5771          44 :     containerLayer->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(pixBounds));
    5772             :   }
    5773         239 :   if (aParameters.mLayerContentsVisibleRect) {
    5774          52 :     *aParameters.mLayerContentsVisibleRect = pixBounds + scaleParameters.mOffset;
    5775             :   }
    5776             : 
    5777         239 :   mContainerLayerGeneration = oldGeneration;
    5778         239 :   nsPresContext::ClearNotifySubDocInvalidationData(containerLayer);
    5779             : 
    5780         239 :   return containerLayer.forget();
    5781             : }
    5782             : 
    5783             : Layer*
    5784          24 : FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
    5785             :                                    nsDisplayItem* aItem)
    5786             : {
    5787          24 :   Layer* layer = GetOldLayerFor(aItem);
    5788          24 :   if (!layer)
    5789           1 :     return nullptr;
    5790          23 :   if (layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
    5791             :     // This layer was created to render Thebes-rendered content for this
    5792             :     // display item. The display item should not use it for its own
    5793             :     // layer rendering.
    5794           0 :     return nullptr;
    5795             :   }
    5796          23 :   ResetLayerStateForRecycling(layer);
    5797          23 :   return layer;
    5798             : }
    5799             : 
    5800             : /* static */ void
    5801           1 : FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
    5802             : {
    5803             :   LayerManagerData* data = static_cast<LayerManagerData*>
    5804           1 :     (aManager->GetUserData(&gLayerManagerUserData));
    5805           1 :   if (data) {
    5806           0 :     data->mInvalidateAllLayers = true;
    5807             :   }
    5808           1 : }
    5809             : 
    5810             : /* static */ void
    5811           0 : FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame)
    5812             : {
    5813           0 :   const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
    5814             : 
    5815           0 :   for (uint32_t i = 0; i < array.Length(); i++) {
    5816           0 :     DisplayItemData::AssertDisplayItemData(array.ElementAt(i))->mParent->mInvalidateAllLayers = true;
    5817             :   }
    5818           0 : }
    5819             : 
    5820             : /* static */
    5821             : Layer*
    5822        2442 : FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey)
    5823             : {
    5824             :   //TODO: This isn't completely correct, since a frame could exist as a layer
    5825             :   // in the normal widget manager, and as a different layer (or no layer)
    5826             :   // in the secondary manager
    5827             : 
    5828        2442 :   const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();;
    5829             : 
    5830        2727 :   for (uint32_t i = 0; i < array.Length(); i++) {
    5831         286 :     DisplayItemData *element = DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
    5832         286 :     if (!element->mParent->mLayerManager->IsWidgetLayerManager()) {
    5833          44 :       continue;
    5834             :     }
    5835         242 :     if (element->mDisplayItemKey == aDisplayItemKey) {
    5836          35 :       if (element->mOptLayer) {
    5837           0 :         return element->mOptLayer;
    5838             :       }
    5839             : 
    5840             : 
    5841          35 :       Layer* layer = element->mLayer;
    5842         105 :       if (!layer->HasUserData(&gColorLayerUserData) &&
    5843          70 :           !layer->HasUserData(&gImageLayerUserData) &&
    5844          35 :           !layer->HasUserData(&gPaintedDisplayItemLayerUserData)) {
    5845           1 :         return layer;
    5846             :       }
    5847             :     }
    5848             :   }
    5849        2441 :   return nullptr;
    5850             : }
    5851             : 
    5852             : static gfxSize
    5853         544 : PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale,
    5854             :                        const gfxSize& aScale)
    5855             : {
    5856         544 :   Matrix4x4 transform = Matrix4x4::Scaling(aScale.width, aScale.height, 1.0);
    5857         544 :   if (aFrame != aAncestorWithScale) {
    5858             :     // aTransform is applied first, then the scale is applied to the result
    5859         544 :     transform = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestorWithScale)*transform;
    5860             :   }
    5861         544 :   Matrix transform2d;
    5862         544 :   if (transform.CanDraw2D(&transform2d)) {
    5863         544 :      return ThebesMatrix(transform2d).ScaleFactors(true);
    5864             :   }
    5865           0 :   return gfxSize(1.0, 1.0);
    5866             : }
    5867             : 
    5868             : gfxSize
    5869         544 : FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame)
    5870             : {
    5871         544 :   MOZ_ASSERT(aFrame, "need a frame");
    5872         544 :   nsIFrame* last = nullptr;
    5873        4391 :   for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
    5874        3847 :     last = f;
    5875             : 
    5876        3847 :     if (nsLayoutUtils::IsPopup(f)) {
    5877             :       // Don't examine ancestors of a popup. It won't make sense to check
    5878             :       // the transform from some content inside the popup to some content
    5879             :       // which is an ancestor of the popup.
    5880           0 :       break;
    5881             :     }
    5882             : 
    5883        3847 :     const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
    5884             : 
    5885        3850 :     for (uint32_t i = 0; i < array.Length(); i++) {
    5886           3 :       Layer* layer = DisplayItemData::AssertDisplayItemData(array.ElementAt(i))->mLayer;
    5887           3 :       ContainerLayer* container = layer->AsContainerLayer();
    5888           3 :       if (!container ||
    5889           0 :           !layer->Manager()->IsWidgetLayerManager()) {
    5890           3 :         continue;
    5891             :       }
    5892           0 :       for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
    5893             :         PaintedDisplayItemLayerUserData* data =
    5894             :             static_cast<PaintedDisplayItemLayerUserData*>
    5895           0 :               (l->GetUserData(&gPaintedDisplayItemLayerUserData));
    5896           0 :         if (data) {
    5897           0 :           return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale));
    5898             :         }
    5899             :       }
    5900             :     }
    5901             :   }
    5902             : 
    5903         544 :   float presShellResolution = last->PresContext()->PresShell()->GetResolution();
    5904             :   return PredictScaleForContent(aFrame, last,
    5905         544 :       gfxSize(presShellResolution, presShellResolution));
    5906             : }
    5907             : 
    5908             : #ifdef MOZ_DUMP_PAINTING
    5909           0 : static void DebugPaintItem(DrawTarget& aDrawTarget,
    5910             :                            nsPresContext* aPresContext,
    5911             :                            nsDisplayItem *aItem,
    5912             :                            nsDisplayListBuilder* aBuilder)
    5913             : {
    5914             :   bool snap;
    5915           0 :   Rect bounds = NSRectToRect(aItem->GetBounds(aBuilder, &snap),
    5916           0 :                              aPresContext->AppUnitsPerDevPixel());
    5917             : 
    5918             :   RefPtr<DrawTarget> tempDT =
    5919           0 :     aDrawTarget.CreateSimilarDrawTarget(IntSize::Truncate(bounds.width, bounds.height),
    5920           0 :                                         SurfaceFormat::B8G8R8A8);
    5921           0 :   RefPtr<gfxContext> context = gfxContext::CreateOrNull(tempDT);
    5922           0 :   if (!context) {
    5923             :     // Leave this as crash, it's in the debugging code, we want to know
    5924           0 :     gfxDevCrash(LogReason::InvalidContext) << "DebugPaintItem context problem " << gfx::hexa(tempDT);
    5925           0 :     return;
    5926             :   }
    5927           0 :   context->SetMatrix(gfxMatrix::Translation(-bounds.x, -bounds.y));
    5928             : 
    5929           0 :   aItem->Paint(aBuilder, context);
    5930           0 :   RefPtr<SourceSurface> surface = tempDT->Snapshot();
    5931           0 :   DumpPaintedImage(aItem, surface);
    5932             : 
    5933           0 :   aDrawTarget.DrawSurface(surface, bounds, Rect(Point(0,0), bounds.Size()));
    5934             : 
    5935           0 :   aItem->SetPainted();
    5936             : }
    5937             : #endif
    5938             : 
    5939             : /* static */ void
    5940          60 : FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray<ClippedDisplayItem>& aItems,
    5941             :                                                nsDisplayListBuilder *aBuilder,
    5942             :                                                const nsIntRegion& aRegionToDraw,
    5943             :                                                const nsIntPoint& aOffset,
    5944             :                                                int32_t aAppUnitsPerDevPixel,
    5945             :                                                float aXScale,
    5946             :                                                float aYScale)
    5947             : {
    5948             :   uint32_t i;
    5949             :   // Update visible regions. We perform visibility analysis to take account
    5950             :   // of occlusion culling.
    5951         120 :   nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel);
    5952          60 :   visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel),
    5953         120 :                  NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel));
    5954          60 :   visible.ScaleInverseRoundOut(aXScale, aYScale);
    5955             : 
    5956         833 :   for (i = aItems.Length(); i > 0; --i) {
    5957         773 :     ClippedDisplayItem* cdi = &aItems[i - 1];
    5958         773 :     const DisplayItemClip& clip = cdi->mItem->GetClip();
    5959             : 
    5960         773 :     NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel,
    5961             :                  "a painted layer should contain items only at the same zoom");
    5962             : 
    5963         773 :     MOZ_ASSERT(clip.HasClip() || clip.GetRoundedRectCount() == 0,
    5964             :                "If we have rounded rects, we must have a clip rect");
    5965             : 
    5966         773 :     if (!clip.IsRectAffectedByClip(visible.GetBounds())) {
    5967         420 :       cdi->mItem->RecomputeVisibility(aBuilder, &visible);
    5968         420 :       continue;
    5969             :     }
    5970             : 
    5971             :     // Do a little dance to account for the fact that we're clipping
    5972             :     // to cdi->mClipRect
    5973         706 :     nsRegion clipped;
    5974         353 :     clipped.And(visible, clip.NonRoundedIntersection());
    5975         706 :     nsRegion finalClipped = clipped;
    5976         353 :     cdi->mItem->RecomputeVisibility(aBuilder, &finalClipped);
    5977             :     // If we have rounded clip rects, don't subtract from the visible
    5978             :     // region since we aren't displaying everything inside the rect.
    5979         353 :     if (clip.GetRoundedRectCount() == 0) {
    5980         636 :       nsRegion removed;
    5981         318 :       removed.Sub(clipped, finalClipped);
    5982         636 :       nsRegion newVisible;
    5983         318 :       newVisible.Sub(visible, removed);
    5984             :       // Don't let the visible region get too complex.
    5985         318 :       if (newVisible.GetNumRects() <= 15) {
    5986         318 :         visible = newVisible;
    5987             :       }
    5988             :     }
    5989             :   }
    5990          60 : }
    5991             : 
    5992             : void
    5993          84 : FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
    5994             :                               const nsIntRect& aRect,
    5995             :                               gfxContext *aContext,
    5996             :                               gfxContext *aRC,
    5997             :                               nsDisplayListBuilder* aBuilder,
    5998             :                               nsPresContext* aPresContext,
    5999             :                               const nsIntPoint& aOffset,
    6000             :                               float aXScale, float aYScale,
    6001             :                               int32_t aCommonClipCount)
    6002             : {
    6003          84 :   DrawTarget& aDrawTarget = *aRC->GetDrawTarget();
    6004             : 
    6005          84 :   int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
    6006         168 :   nsRect boundRect = ToAppUnits(aRect, appUnitsPerDevPixel);
    6007          84 :   boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
    6008         168 :                  NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
    6009          84 :   boundRect.ScaleInverseRoundOut(aXScale, aYScale);
    6010             : 
    6011         168 :   DisplayItemClip currentClip;
    6012          84 :   bool currentClipIsSetInContext = false;
    6013         168 :   DisplayItemClip tmpClip;
    6014             : 
    6015         895 :   for (uint32_t i = 0; i < aItems.Length(); ++i) {
    6016         811 :     ClippedDisplayItem* cdi = &aItems[i];
    6017             : 
    6018        1150 :     nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect);
    6019         811 :     if (paintRect.IsEmpty())
    6020         472 :       continue;
    6021             : 
    6022             : #ifdef MOZ_DUMP_PAINTING
    6023         678 :     AUTO_PROFILER_LABEL_DYNAMIC("FrameLayerBuilder::PaintItems", GRAPHICS,
    6024             :                                 cdi->mItem->Name());
    6025             : #else
    6026             :     AUTO_PROFILER_LABEL("FrameLayerBuilder::PaintItems", GRAPHICS);
    6027             : #endif
    6028             : 
    6029             :     // If the new desired clip state is different from the current state,
    6030             :     // update the clip.
    6031         339 :     const DisplayItemClip* clip = &cdi->mItem->GetClip();
    6032         368 :     if (clip->GetRoundedRectCount() > 0 &&
    6033          29 :         !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
    6034           8 :       tmpClip = *clip;
    6035           8 :       tmpClip.RemoveRoundedCorners();
    6036           8 :       clip = &tmpClip;
    6037             :     }
    6038         815 :     if (currentClipIsSetInContext != clip->HasClip() ||
    6039         457 :         (clip->HasClip() && *clip != currentClip)) {
    6040         217 :       if (currentClipIsSetInContext) {
    6041         153 :         aContext->Restore();
    6042             :       }
    6043         217 :       currentClipIsSetInContext = clip->HasClip();
    6044         217 :       if (currentClipIsSetInContext) {
    6045         201 :         currentClip = *clip;
    6046         201 :         aContext->Save();
    6047         201 :         NS_ASSERTION(aCommonClipCount < 100,
    6048             :           "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong.");
    6049         201 :         currentClip.ApplyTo(aContext, aPresContext, aCommonClipCount);
    6050         201 :         aContext->NewPath();
    6051             :       }
    6052             :     }
    6053             : 
    6054         339 :     if (cdi->mInactiveLayerManager) {
    6055          30 :       bool saved = aDrawTarget.GetPermitSubpixelAA();
    6056          30 :       PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aRC);
    6057          30 :       aDrawTarget.SetPermitSubpixelAA(saved);
    6058             :     } else {
    6059         309 :       nsIFrame* frame = cdi->mItem->Frame();
    6060         309 :       if (aBuilder->IsPaintingToWindow()) {
    6061         271 :         frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
    6062             :       }
    6063             : #ifdef MOZ_DUMP_PAINTING
    6064         309 :       if (gfxEnv::DumpPaintItems()) {
    6065           0 :         DebugPaintItem(aDrawTarget, aPresContext, cdi->mItem, aBuilder);
    6066             :       } else
    6067             : #endif
    6068             :       {
    6069         309 :         cdi->mItem->Paint(aBuilder, aRC);
    6070             :       }
    6071             :     }
    6072             : 
    6073         339 :     if (CheckDOMModified())
    6074           0 :       break;
    6075             :   }
    6076             : 
    6077          84 :   if (currentClipIsSetInContext) {
    6078          48 :     aContext->Restore();
    6079             :   }
    6080          84 : }
    6081             : 
    6082             : /**
    6083             :  * Returns true if it is preferred to draw the list of display
    6084             :  * items separately for each rect in the visible region rather
    6085             :  * than clipping to a complex region.
    6086             :  */
    6087             : static bool
    6088          84 : ShouldDrawRectsSeparately(DrawTarget* aDrawTarget, DrawRegionClip aClip)
    6089             : {
    6090          84 :   if (!gfxPrefs::LayoutPaintRectsSeparately() ||
    6091             :       aClip == DrawRegionClip::NONE) {
    6092          51 :     return false;
    6093             :   }
    6094             : 
    6095          33 :   return !aDrawTarget->SupportsRegionClipping();
    6096             : }
    6097             : 
    6098          84 : static void DrawForcedBackgroundColor(DrawTarget& aDrawTarget,
    6099             :                                       const IntRect& aBounds,
    6100             :                                       nscolor aBackgroundColor)
    6101             : {
    6102          84 :   if (NS_GET_A(aBackgroundColor) > 0) {
    6103           0 :     ColorPattern color(ToDeviceColor(aBackgroundColor));
    6104           0 :     aDrawTarget.FillRect(Rect(aBounds), color);
    6105             :   }
    6106          84 : }
    6107             : 
    6108             : /*
    6109             :  * A note on residual transforms:
    6110             :  *
    6111             :  * In a transformed subtree we sometimes apply the PaintedLayer's
    6112             :  * "residual transform" when drawing content into the PaintedLayer.
    6113             :  * This is a translation by components in the range [-0.5,0.5) provided
    6114             :  * by the layer system; applying the residual transform followed by the
    6115             :  * transforms used by layer compositing ensures that the subpixel alignment
    6116             :  * of the content of the PaintedLayer exactly matches what it would be if
    6117             :  * we used cairo/Thebes to draw directly to the screen without going through
    6118             :  * retained layer buffers.
    6119             :  *
    6120             :  * The visible and valid regions of the PaintedLayer are computed without
    6121             :  * knowing the residual transform (because we don't know what the residual
    6122             :  * transform is going to be until we've built the layer tree!). So we have to
    6123             :  * consider whether content painted in the range [x, xmost) might be painted
    6124             :  * outside the visible region we computed for that content. The visible region
    6125             :  * would be [floor(x), ceil(xmost)). The content would be rendered at
    6126             :  * [x + r, xmost + r), where -0.5 <= r < 0.5. So some half-rendered pixels could
    6127             :  * indeed fall outside the computed visible region, which is not a big deal;
    6128             :  * similar issues already arise when we snap cliprects to nearest pixels.
    6129             :  * Note that if the rendering of the content is snapped to nearest pixels ---
    6130             :  * which it often is --- then the content is actually rendered at
    6131             :  * [snap(x + r), snap(xmost + r)). It turns out that floor(x) <= snap(x + r)
    6132             :  * and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content
    6133             :  * always falls within the visible region we computed.
    6134             :  */
    6135             : 
    6136             : /* static */ void
    6137          84 : FrameLayerBuilder::DrawPaintedLayer(PaintedLayer* aLayer,
    6138             :                                    gfxContext* aContext,
    6139             :                                    const nsIntRegion& aRegionToDraw,
    6140             :                                    const nsIntRegion& aDirtyRegion,
    6141             :                                    DrawRegionClip aClip,
    6142             :                                    const nsIntRegion& aRegionToInvalidate,
    6143             :                                    void* aCallbackData)
    6144             : {
    6145          84 :   DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
    6146             : 
    6147         168 :   AUTO_PROFILER_LABEL("FrameLayerBuilder::DrawPaintedLayer", GRAPHICS);
    6148             : 
    6149             :   nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*>
    6150          84 :     (aCallbackData);
    6151             : 
    6152          84 :   FrameLayerBuilder *layerBuilder = aLayer->Manager()->GetLayerBuilder();
    6153          84 :   NS_ASSERTION(layerBuilder, "Unexpectedly null layer builder!");
    6154             : 
    6155          84 :   if (layerBuilder->CheckDOMModified())
    6156           0 :     return;
    6157             : 
    6158          84 :   PaintedLayerItemsEntry* entry = layerBuilder->mPaintedLayerItems.GetEntry(aLayer);
    6159          84 :   NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!");
    6160          84 :   if (!entry->mContainerLayerFrame) {
    6161           0 :     return;
    6162             :   }
    6163             : 
    6164             : 
    6165             :   PaintedDisplayItemLayerUserData* userData =
    6166             :     static_cast<PaintedDisplayItemLayerUserData*>
    6167          84 :       (aLayer->GetUserData(&gPaintedDisplayItemLayerUserData));
    6168          84 :   NS_ASSERTION(userData, "where did our user data go?");
    6169             : 
    6170             :   bool shouldDrawRectsSeparately =
    6171          84 :     ShouldDrawRectsSeparately(&aDrawTarget, aClip);
    6172             : 
    6173          84 :   if (!shouldDrawRectsSeparately) {
    6174          84 :     if (aClip == DrawRegionClip::DRAW) {
    6175          33 :       gfxUtils::ClipToRegion(aContext, aRegionToDraw);
    6176             :     }
    6177             : 
    6178         168 :     DrawForcedBackgroundColor(aDrawTarget, aRegionToDraw.GetBounds(),
    6179          84 :                               userData->mForcedBackgroundColor);
    6180             :   }
    6181             : 
    6182          84 :   if (NS_GET_A(userData->mFontSmoothingBackgroundColor) > 0) {
    6183             :     aContext->SetFontSmoothingBackgroundColor(
    6184           0 :       Color::FromABGR(userData->mFontSmoothingBackgroundColor));
    6185             :   }
    6186             : 
    6187             :   // make the origin of the context coincide with the origin of the
    6188             :   // PaintedLayer
    6189         168 :   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
    6190          84 :   nsIntPoint offset = GetTranslationForPaintedLayer(aLayer);
    6191          84 :   nsPresContext* presContext = entry->mContainerLayerFrame->PresContext();
    6192             : 
    6193         168 :   if (!userData->mVisibilityComputedRegion.Contains(aDirtyRegion) &&
    6194          84 :       !layerBuilder->GetContainingPaintedLayerData()) {
    6195             :     // Recompute visibility of items in our PaintedLayer, if required. Note
    6196             :     // that this recomputes visibility for all descendants of our display
    6197             :     // items too, so there's no need to do this for the items in inactive
    6198             :     // PaintedLayers. If aDirtyRegion has not changed since the previous call
    6199             :     // then we can skip this.
    6200          60 :     int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
    6201          60 :     RecomputeVisibilityForItems(entry->mItems, builder, aDirtyRegion,
    6202             :                                 offset, appUnitsPerDevPixel,
    6203          60 :                                 userData->mXScale, userData->mYScale);
    6204          60 :     userData->mVisibilityComputedRegion = aDirtyRegion;
    6205             :   }
    6206             : 
    6207          84 :   if (shouldDrawRectsSeparately) {
    6208           0 :     for (auto iter = aRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
    6209           0 :       const nsIntRect& iterRect = iter.Get();
    6210           0 :       gfxContextAutoSaveRestore save(aContext);
    6211           0 :       aContext->NewPath();
    6212           0 :       aContext->Rectangle(ThebesRect(iterRect));
    6213           0 :       aContext->Clip();
    6214             : 
    6215           0 :       DrawForcedBackgroundColor(aDrawTarget, iterRect,
    6216           0 :                                 userData->mForcedBackgroundColor);
    6217             : 
    6218             :       // Apply the residual transform if it has been enabled, to ensure that
    6219             :       // snapping when we draw into aContext exactly matches the ideal transform.
    6220             :       // See above for why this is OK.
    6221             :       aContext->SetMatrix(
    6222           0 :         aContext->CurrentMatrix().PreTranslate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)).
    6223           0 :                                   PreScale(userData->mXScale, userData->mYScale));
    6224             : 
    6225           0 :       layerBuilder->PaintItems(entry->mItems, iterRect, aContext, aContext,
    6226             :                                builder, presContext,
    6227             :                                offset, userData->mXScale, userData->mYScale,
    6228           0 :                                entry->mCommonClipCount);
    6229           0 :       if (gfxPrefs::GfxLoggingPaintedPixelCountEnabled()) {
    6230           0 :         aLayer->Manager()->AddPaintedPixelCount(iterRect.Area());
    6231             :       }
    6232             :     }
    6233             :   } else {
    6234             :     // Apply the residual transform if it has been enabled, to ensure that
    6235             :     // snapping when we draw into aContext exactly matches the ideal transform.
    6236             :     // See above for why this is OK.
    6237             :     aContext->SetMatrix(
    6238         168 :       aContext->CurrentMatrix().PreTranslate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)).
    6239         168 :                                 PreScale(userData->mXScale,userData->mYScale));
    6240             : 
    6241         168 :     layerBuilder->PaintItems(entry->mItems, aRegionToDraw.GetBounds(), aContext, aContext,
    6242             :                              builder, presContext,
    6243             :                              offset, userData->mXScale, userData->mYScale,
    6244         168 :                              entry->mCommonClipCount);
    6245          84 :     if (gfxPrefs::GfxLoggingPaintedPixelCountEnabled()) {
    6246           0 :       aLayer->Manager()->AddPaintedPixelCount(
    6247           0 :         aRegionToDraw.GetBounds().Area());
    6248             :     }
    6249             :   }
    6250             : 
    6251          84 :   aContext->SetFontSmoothingBackgroundColor(Color());
    6252             : 
    6253          84 :   bool isActiveLayerManager = !aLayer->Manager()->IsInactiveLayerManager();
    6254             : 
    6255          84 :   if (presContext->GetPaintFlashing() && isActiveLayerManager) {
    6256           0 :     gfxContextAutoSaveRestore save(aContext);
    6257           0 :     if (shouldDrawRectsSeparately) {
    6258           0 :       if (aClip == DrawRegionClip::DRAW) {
    6259           0 :         gfxUtils::ClipToRegion(aContext, aRegionToDraw);
    6260             :       }
    6261             :     }
    6262           0 :     FlashPaint(aContext);
    6263             :   }
    6264             : 
    6265          84 :   if (presContext->GetDocShell() && isActiveLayerManager) {
    6266          33 :     nsDocShell* docShell = static_cast<nsDocShell*>(presContext->GetDocShell());
    6267          66 :     RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
    6268             : 
    6269          33 :     if (timelines && timelines->HasConsumer(docShell)) {
    6270           0 :       timelines->AddMarkerForDocShell(docShell, Move(
    6271           0 :         MakeUnique<LayerTimelineMarker>(aRegionToDraw)));
    6272             :     }
    6273             :   }
    6274             : 
    6275          84 :   if (!aRegionToInvalidate.IsEmpty()) {
    6276           0 :     aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds());
    6277             :   }
    6278             : }
    6279             : 
    6280             : bool
    6281         423 : FrameLayerBuilder::CheckDOMModified()
    6282             : {
    6283         846 :   if (!mRootPresContext ||
    6284         423 :       mInitialDOMGeneration == mRootPresContext->GetDOMGeneration())
    6285         423 :     return false;
    6286           0 :   if (mDetectedDOMModification) {
    6287             :     // Don't spam the console with extra warnings
    6288           0 :     return true;
    6289             :   }
    6290           0 :   mDetectedDOMModification = true;
    6291             :   // Painting is not going to complete properly. There's not much
    6292             :   // we can do here though. Invalidating the window to get another repaint
    6293             :   // is likely to lead to an infinite repaint loop.
    6294           0 :   NS_WARNING("Detected DOM modification during paint, bailing out!");
    6295           0 :   return true;
    6296             : }
    6297             : 
    6298             : /* static */ void
    6299           0 : FrameLayerBuilder::DumpRetainedLayerTree(LayerManager* aManager, std::stringstream& aStream, bool aDumpHtml)
    6300             : {
    6301           0 :   aManager->Dump(aStream, "", aDumpHtml);
    6302           0 : }
    6303             : 
    6304             : nsDisplayItemGeometry*
    6305         325 : FrameLayerBuilder::GetMostRecentGeometry(nsDisplayItem* aItem)
    6306             : {
    6307             :   typedef SmallPointerArray<DisplayItemData> DataArray;
    6308             : 
    6309             :   // Retrieve the array of DisplayItemData associated with our frame.
    6310         325 :   const DataArray& dataArray = aItem->Frame()->DisplayItemData();
    6311             : 
    6312             :   // Find our display item data, if it exists, and return its geometry.
    6313         325 :   uint32_t itemPerFrameKey = aItem->GetPerFrameKey();
    6314         590 :   for (uint32_t i = 0; i < dataArray.Length(); i++) {
    6315         552 :     DisplayItemData* data = DisplayItemData::AssertDisplayItemData(dataArray.ElementAt(i));
    6316         552 :     if (data->GetDisplayItemKey() == itemPerFrameKey) {
    6317         287 :       return data->GetGeometry();
    6318             :     }
    6319             :   }
    6320             : 
    6321          38 :   return nullptr;
    6322             : }
    6323             : 
    6324             : static gfx::Rect
    6325           0 : CalculateBounds(const nsTArray<DisplayItemClip::RoundedRect>& aRects, int32_t aAppUnitsPerDevPixel)
    6326             : {
    6327           0 :   nsRect bounds = aRects[0].mRect;
    6328           0 :   for (uint32_t i = 1; i < aRects.Length(); ++i) {
    6329           0 :     bounds.UnionRect(bounds, aRects[i].mRect);
    6330             :    }
    6331             : 
    6332           0 :   return gfx::Rect(bounds.ToNearestPixels(aAppUnitsPerDevPixel));
    6333             : }
    6334             : 
    6335             : static void
    6336         258 : SetClipCount(PaintedDisplayItemLayerUserData* apaintedData,
    6337             :              uint32_t aClipCount)
    6338             : {
    6339         258 :   if (apaintedData) {
    6340         255 :     apaintedData->mMaskClipCount = aClipCount;
    6341             :   }
    6342         258 : }
    6343             : 
    6344             : void
    6345         258 : ContainerState::SetupMaskLayer(Layer *aLayer,
    6346             :                                const DisplayItemClip& aClip,
    6347             :                                uint32_t aRoundedRectClipCount)
    6348             : {
    6349             :   // if the number of clips we are going to mask has decreased, then aLayer might have
    6350             :   // cached graphics which assume the existence of a soon-to-be non-existent mask layer
    6351             :   // in that case, invalidate the whole layer.
    6352         258 :   PaintedDisplayItemLayerUserData* paintedData = GetPaintedDisplayItemLayerUserData(aLayer);
    6353         513 :   if (paintedData &&
    6354         255 :       aRoundedRectClipCount < paintedData->mMaskClipCount) {
    6355           0 :     PaintedLayer* painted = aLayer->AsPaintedLayer();
    6356           0 :     painted->InvalidateWholeLayer();
    6357             :   }
    6358             : 
    6359             :   // don't build an unnecessary mask
    6360         258 :   if (aClip.GetRoundedRectCount() == 0 ||
    6361             :       aRoundedRectClipCount == 0) {
    6362         258 :     SetClipCount(paintedData, 0);
    6363         258 :     return;
    6364             :   }
    6365             : 
    6366             :   RefPtr<Layer> maskLayer =
    6367           0 :     CreateMaskLayer(aLayer, aClip, Nothing(), aRoundedRectClipCount);
    6368             : 
    6369           0 :   if (!maskLayer) {
    6370           0 :     SetClipCount(paintedData, 0);
    6371           0 :     return;
    6372             :   }
    6373             : 
    6374           0 :   aLayer->SetMaskLayer(maskLayer);
    6375           0 :   SetClipCount(paintedData, aRoundedRectClipCount);
    6376             : }
    6377             : 
    6378             : already_AddRefed<Layer>
    6379           0 : ContainerState::CreateMaskLayer(Layer *aLayer,
    6380             :                                const DisplayItemClip& aClip,
    6381             :                                const Maybe<size_t>& aForAncestorMaskLayer,
    6382             :                                uint32_t aRoundedRectClipCount)
    6383             : {
    6384             :   // aLayer will never be the container layer created by an nsDisplayMask
    6385             :   // because nsDisplayMask propagates the DisplayItemClip to its contents
    6386             :   // and is not clipped itself.
    6387             :   // This assertion will fail if that ever stops being the case.
    6388           0 :   MOZ_ASSERT(!aLayer->GetUserData(&gCSSMaskLayerUserData),
    6389             :              "A layer contains round clips should not have css-mask on it.");
    6390             : 
    6391             :   // check if we can re-use the mask layer
    6392           0 :   MaskLayerKey recycleKey(aLayer, aForAncestorMaskLayer);
    6393             :   RefPtr<ImageLayer> maskLayer =
    6394           0 :     CreateOrRecycleMaskImageLayerFor(recycleKey,
    6395           0 :       [](Layer* aMaskLayer)
    6396             :       {
    6397           0 :         aMaskLayer->SetUserData(&gMaskLayerUserData,
    6398           0 :                                 new MaskLayerUserData());
    6399           0 :       }
    6400           0 :     );
    6401           0 :   MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer);
    6402             : 
    6403           0 :   int32_t A2D = mContainerFrame->PresContext()->AppUnitsPerDevPixel();
    6404           0 :   MaskLayerUserData newData(aClip, aRoundedRectClipCount, A2D, mParameters);
    6405           0 :   if (*userData == newData) {
    6406           0 :     return maskLayer.forget();
    6407             :   }
    6408             : 
    6409             :   gfx::Rect boundingRect = CalculateBounds(newData.mRoundedClipRects,
    6410           0 :                                            newData.mAppUnitsPerDevPixel);
    6411           0 :   boundingRect.Scale(mParameters.mXScale, mParameters.mYScale);
    6412             : 
    6413           0 :   uint32_t maxSize = mManager->GetMaxTextureSize();
    6414           0 :   NS_ASSERTION(maxSize > 0, "Invalid max texture size");
    6415             : #ifdef MOZ_GFX_OPTIMIZE_MOBILE
    6416             :   // Make mask image width aligned to 4. See Bug 1245552.
    6417             :   gfx::Size surfaceSize(std::min<gfx::Float>(GetAlignedStride<4>(NSToIntCeil(boundingRect.Width()), 1), maxSize),
    6418             :                         std::min<gfx::Float>(boundingRect.Height(), maxSize));
    6419             : #else
    6420           0 :   gfx::Size surfaceSize(std::min<gfx::Float>(boundingRect.Width(), maxSize),
    6421           0 :                         std::min<gfx::Float>(boundingRect.Height(), maxSize));
    6422             : #endif
    6423             : 
    6424             :   // maskTransform is applied to the clip when it is painted into the mask (as a
    6425             :   // component of imageTransform), and its inverse used when the mask is used for
    6426             :   // masking.
    6427             :   // It is the transform from the masked layer's space to mask space
    6428             :   gfx::Matrix maskTransform =
    6429           0 :     Matrix::Scaling(surfaceSize.width / boundingRect.Width(),
    6430           0 :                     surfaceSize.height / boundingRect.Height());
    6431           0 :   if (surfaceSize.IsEmpty()) {
    6432             :     // Return early if we know that the size of this mask surface is empty.
    6433           0 :     return nullptr;
    6434             :   }
    6435             : 
    6436           0 :   gfx::Point p = boundingRect.TopLeft();
    6437           0 :   maskTransform.PreTranslate(-p.x, -p.y);
    6438             :   // imageTransform is only used when the clip is painted to the mask
    6439           0 :   gfx::Matrix imageTransform = maskTransform;
    6440           0 :   imageTransform.PreScale(mParameters.mXScale, mParameters.mYScale);
    6441             : 
    6442             :   nsAutoPtr<MaskLayerImageCache::MaskLayerImageKey> newKey(
    6443           0 :     new MaskLayerImageCache::MaskLayerImageKey());
    6444             : 
    6445             :   // copy and transform the rounded rects
    6446           0 :   for (uint32_t i = 0; i < newData.mRoundedClipRects.Length(); ++i) {
    6447           0 :     newKey->mRoundedClipRects.AppendElement(
    6448           0 :       MaskLayerImageCache::PixelRoundedRect(newData.mRoundedClipRects[i],
    6449           0 :                                             mContainerFrame->PresContext()));
    6450           0 :     newKey->mRoundedClipRects[i].ScaleAndTranslate(imageTransform);
    6451             :   }
    6452           0 :   newKey->mForwarder = mManager->AsShadowForwarder();
    6453             : 
    6454           0 :   const MaskLayerImageCache::MaskLayerImageKey* lookupKey = newKey;
    6455             : 
    6456             :   // check to see if we can reuse a mask image
    6457             :   RefPtr<ImageContainer> container =
    6458           0 :     GetMaskLayerImageCache()->FindImageFor(&lookupKey);
    6459             : 
    6460           0 :   if (!container) {
    6461             :     IntSize surfaceSizeInt(NSToIntCeil(surfaceSize.width),
    6462           0 :                            NSToIntCeil(surfaceSize.height));
    6463             :     // no existing mask image, so build a new one
    6464           0 :     MaskImageData imageData(surfaceSizeInt, mManager);
    6465           0 :     RefPtr<DrawTarget> dt = imageData.CreateDrawTarget();
    6466             : 
    6467             :     // fail if we can't get the right surface
    6468           0 :     if (!dt || !dt->IsValid()) {
    6469           0 :       NS_WARNING("Could not create DrawTarget for mask layer.");
    6470           0 :       return nullptr;
    6471             :     }
    6472             : 
    6473           0 :     RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
    6474           0 :     MOZ_ASSERT(context); // already checked the draw target above
    6475           0 :     context->Multiply(ThebesMatrix(imageTransform));
    6476             : 
    6477             :     // paint the clipping rects with alpha to create the mask
    6478           0 :     aClip.FillIntersectionOfRoundedRectClips(context,
    6479           0 :                                              Color(1.f, 1.f, 1.f, 1.f),
    6480             :                                              newData.mAppUnitsPerDevPixel,
    6481             :                                              0,
    6482           0 :                                              aRoundedRectClipCount);
    6483             : 
    6484             :     // build the image and container
    6485           0 :     MOZ_ASSERT(aLayer->Manager() == mManager);
    6486           0 :     container = imageData.CreateImageAndImageContainer();
    6487           0 :     NS_ASSERTION(container, "Could not create image container for mask layer.");
    6488             : 
    6489           0 :     if (!container) {
    6490           0 :       return nullptr;
    6491             :     }
    6492             : 
    6493           0 :     GetMaskLayerImageCache()->PutImage(newKey.forget(), container);
    6494             :   }
    6495             : 
    6496           0 :   maskLayer->SetContainer(container);
    6497             : 
    6498           0 :   maskTransform.Invert();
    6499           0 :   Matrix4x4 matrix = Matrix4x4::From2D(maskTransform);
    6500           0 :   matrix.PreTranslate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
    6501           0 :   maskLayer->SetBaseTransform(matrix);
    6502             : 
    6503             :   // save the details of the clip in user data
    6504           0 :   *userData = Move(newData);
    6505           0 :   userData->mImageKey.Reset(lookupKey);
    6506             : 
    6507           0 :   return maskLayer.forget();
    6508             : }
    6509             : 
    6510             : } // namespace mozilla

Generated by: LCOV version 1.13