LCOV - code coverage report
Current view: top level - layout/painting - FrameLayerBuilder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 806 2511 32.1 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13-14-ga5dd952