layout/base/FrameLayerBuilder.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/DebugOnly.h"
     8 #include "FrameLayerBuilder.h"
    10 #include "nsDisplayList.h"
    11 #include "nsPresContext.h"
    12 #include "nsLayoutUtils.h"
    13 #include "Layers.h"
    14 #include "BasicLayers.h"
    15 #include "gfxUtils.h"
    16 #include "nsRenderingContext.h"
    17 #include "MaskLayerImageCache.h"
    18 #include "nsIScrollableFrame.h"
    19 #include "nsPrintfCString.h"
    20 #include "LayerTreeInvalidation.h"
    21 #include "nsSVGIntegrationUtils.h"
    22 #include "ImageContainer.h"
    23 #include "ActiveLayerTracker.h"
    24 #include "gfx2DGlue.h"
    26 #include "GeckoProfiler.h"
    27 #include "mozilla/gfx/Tools.h"
    28 #include "mozilla/gfx/2D.h"
    29 #include "gfxPrefs.h"
    31 #include <algorithm>
    33 using namespace mozilla::layers;
    34 using namespace mozilla::gfx;
    36 namespace mozilla {
    38 class ContainerState;
    40 FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey,
    41                                                     Layer* aLayer, LayerState aLayerState, uint32_t aGeneration)
    43   : mParent(aParent)
    44   , mLayer(aLayer)
    45   , mDisplayItemKey(aKey)
    46   , mContainerLayerGeneration(aGeneration)
    47   , mLayerState(aLayerState)
    48   , mUsed(true)
    49   , mIsInvalid(false)
    50 {
    51 }
    53 FrameLayerBuilder::DisplayItemData::DisplayItemData(DisplayItemData &toCopy)
    54 {
    55   // This isn't actually a copy-constructor; notice that it steals toCopy's
    56   // mGeometry pointer.  Be careful.
    57   mParent = toCopy.mParent;
    58   mLayer = toCopy.mLayer;
    59   mInactiveManager = toCopy.mInactiveManager;
    60   mFrameList = toCopy.mFrameList;
    61   mGeometry = toCopy.mGeometry;
    62   mDisplayItemKey = toCopy.mDisplayItemKey;
    63   mClip = toCopy.mClip;
    64   mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
    65   mLayerState = toCopy.mLayerState;
    66   mUsed = toCopy.mUsed;
    67 }
    69 void
    70 FrameLayerBuilder::DisplayItemData::AddFrame(nsIFrame* aFrame)
    71 {
    72   mFrameList.AppendElement(aFrame);
    74   nsTArray<DisplayItemData*> *array =
    75     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()));
    76   if (!array) {
    77     array = new nsTArray<DisplayItemData*>();
    78     aFrame->Properties().Set(FrameLayerBuilder::LayerManagerDataProperty(), array);
    79   }
    80   array->AppendElement(this);
    81 }
    83 void
    84 FrameLayerBuilder::DisplayItemData::RemoveFrame(nsIFrame* aFrame)
    85 {
    86   DebugOnly<bool> result = mFrameList.RemoveElement(aFrame);
    87   NS_ASSERTION(result, "Can't remove a frame that wasn't added!");
    89   nsTArray<DisplayItemData*> *array =
    90     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()));
    91   NS_ASSERTION(array, "Must be already stored on the frame!");
    92   array->RemoveElement(this);
    93 }
    95 void
    96 FrameLayerBuilder::DisplayItemData::UpdateContents(Layer* aLayer, LayerState aState,
    97                                                    uint32_t aContainerLayerGeneration,
    98                                                    nsDisplayItem* aItem /* = nullptr */)
    99 {
   100   mLayer = aLayer;
   101   mOptLayer = nullptr;
   102   mInactiveManager = nullptr;
   103   mLayerState = aState;
   104   mContainerLayerGeneration = aContainerLayerGeneration;
   105   mGeometry = nullptr;
   106   mClip = DisplayItemClip();
   107   mUsed = true;
   109   if (!aItem) {
   110     return;
   111   }
   113   nsAutoTArray<nsIFrame*, 4> copy(mFrameList);
   114   if (!copy.RemoveElement(aItem->Frame())) {
   115     AddFrame(aItem->Frame());
   116   }
   118   nsAutoTArray<nsIFrame*,4> mergedFrames;
   119   aItem->GetMergedFrames(&mergedFrames);
   120   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
   121     if (!copy.RemoveElement(mergedFrames[i])) {
   122       AddFrame(mergedFrames[i]);
   123     }
   124   }
   126   for (uint32_t i = 0; i < copy.Length(); i++) {
   127     RemoveFrame(copy[i]);
   128   }
   129 }
   131 static nsIFrame* sDestroyedFrame = nullptr;
   132 FrameLayerBuilder::DisplayItemData::~DisplayItemData()
   133 {
   134   for (uint32_t i = 0; i < mFrameList.Length(); i++) {
   135     nsIFrame* frame = mFrameList[i];
   136     if (frame == sDestroyedFrame) {
   137       continue;
   138     }
   139     nsTArray<DisplayItemData*> *array =
   140       reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->Properties().Get(LayerManagerDataProperty()));
   141     array->RemoveElement(this);
   142   }
   143 }
   145 void
   146 FrameLayerBuilder::DisplayItemData::GetFrameListChanges(nsDisplayItem* aOther,
   147                                                         nsTArray<nsIFrame*>& aOut)
   148 {
   149   aOut = mFrameList;
   150   nsAutoTArray<nsIFrame*, 4> added;
   151   if (!aOut.RemoveElement(aOther->Frame())) {
   152     added.AppendElement(aOther->Frame());
   153   }
   155   nsAutoTArray<nsIFrame*,4> mergedFrames;
   156   aOther->GetMergedFrames(&mergedFrames);
   157   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
   158     if (!aOut.RemoveElement(mergedFrames[i])) {
   159       added.AppendElement(mergedFrames[i]);
   160     }
   161   }
   163   aOut.AppendElements(added);
   164 }
   166 /**
   167  * This is the userdata we associate with a layer manager.
   168  */
   169 class LayerManagerData : public LayerUserData {
   170 public:
   171   LayerManagerData(LayerManager *aManager)
   172     : mLayerManager(aManager)
   173 #ifdef DEBUG_DISPLAY_ITEM_DATA
   174     , mParent(nullptr)
   175 #endif
   176     , mInvalidateAllLayers(false)
   177   {
   178     MOZ_COUNT_CTOR(LayerManagerData);
   179   }
   180   ~LayerManagerData() {
   181     MOZ_COUNT_DTOR(LayerManagerData);
   182   }
   184 #ifdef DEBUG_DISPLAY_ITEM_DATA
   185   void Dump(const char *aPrefix = "") {
   186     printf_stderr("%sLayerManagerData %p\n", aPrefix, this);
   187     nsAutoCString prefix;
   188     prefix += aPrefix;
   189     prefix += "  ";
   190     mDisplayItems.EnumerateEntries(
   191         FrameLayerBuilder::DumpDisplayItemDataForFrame, (void*)prefix.get());
   192   }
   193 #endif
   195   /**
   196    * Tracks which frames have layers associated with them.
   197    */
   198   LayerManager *mLayerManager;
   199 #ifdef DEBUG_DISPLAY_ITEM_DATA
   200   LayerManagerData *mParent;
   201 #endif
   202   nsTHashtable<nsRefPtrHashKey<FrameLayerBuilder::DisplayItemData> > mDisplayItems;
   203   bool mInvalidateAllLayers;
   204 };
   206 /* static */ void
   207 FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame)
   208 {
   209   FrameProperties props = aFrame->Properties();
   210   props.Delete(LayerManagerDataProperty());
   211 }
   213 // a global cache of image containers used for mask layers
   214 static MaskLayerImageCache* gMaskLayerImageCache = nullptr;
   216 static inline MaskLayerImageCache* GetMaskLayerImageCache()
   217 {
   218   if (!gMaskLayerImageCache) {
   219     gMaskLayerImageCache = new MaskLayerImageCache();
   220   }
   222   return gMaskLayerImageCache;
   223 }
   225 /**
   226  * We keep a stack of these to represent the ThebesLayers that are
   227  * currently available to have display items added to.
   228  * We use a stack here because as much as possible we want to
   229  * assign display items to existing ThebesLayers, and to the lowest
   230  * ThebesLayer in z-order. This reduces the number of layers and
   231  * makes it more likely a display item will be rendered to an opaque
   232  * layer, giving us the best chance of getting subpixel AA.
   233  */
   234 class ThebesLayerData {
   235 public:
   236   ThebesLayerData() :
   237     mAnimatedGeometryRoot(nullptr),
   238     mFixedPosFrameForLayerData(nullptr),
   239     mReferenceFrame(nullptr),
   240     mLayer(nullptr),
   241     mIsSolidColorInVisibleRegion(false),
   242     mSingleItemFixedToViewport(false),
   243     mNeedComponentAlpha(false),
   244     mForceTransparentSurface(false),
   245     mImage(nullptr),
   246     mCommonClipCount(-1),
   247     mAllDrawingAbove(false)
   248   {}
   249   /**
   250    * Record that an item has been added to the ThebesLayer, so we
   251    * need to update our regions.
   252    * @param aVisibleRect the area of the item that's visible
   253    * @param aDrawRect the area of the item that would be drawn if it
   254    * was completely visible
   255    * @param aOpaqueRect if non-null, the area of the item that's opaque.
   256    * We pass in a separate opaque rect because the opaque rect can be
   257    * bigger than the visible rect, and we want to have the biggest
   258    * opaque rect that we can.
   259    * @param aSolidColor if non-null, the visible area of the item is
   260    * a constant color given by *aSolidColor
   261    */
   262   void Accumulate(ContainerState* aState,
   263                   nsDisplayItem* aItem,
   264                   const nsIntRect& aVisibleRect,
   265                   const nsIntRect& aDrawRect,
   266                   const DisplayItemClip& aClip);
   267   const nsIFrame* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
   269   /**
   270    * Add aHitRegion and aDispatchToContentHitRegion to the hit regions for
   271    * this ThebesLayer.
   272    */
   273   void AccumulateEventRegions(const nsIntRegion& aHitRegion,
   274                               const nsIntRegion& aMaybeHitRegion,
   275                               const nsIntRegion& aDispatchToContentHitRegion)
   276   {
   277     mHitRegion.Or(mHitRegion, aHitRegion);
   278     mMaybeHitRegion.Or(mMaybeHitRegion, aMaybeHitRegion);
   279     mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aDispatchToContentHitRegion);
   280   }
   282   /**
   283    * If this represents only a nsDisplayImage, and the image type
   284    * supports being optimized to an ImageLayer (TYPE_RASTER only) returns
   285    * an ImageContainer for the image.
   286    */
   287   already_AddRefed<ImageContainer> CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder);
   289   void AddDrawAboveRegion(const nsIntRegion& aAbove)
   290   {
   291     if (!mAllDrawingAbove) {
   292       mDrawAboveRegion.Or(mDrawAboveRegion, aAbove);
   293       mDrawAboveRegion.SimplifyOutward(4);
   294     }
   295   }
   297   void AddVisibleAboveRegion(const nsIntRegion& aAbove)
   298   {
   299     if (!mAllDrawingAbove) {
   300       mVisibleAboveRegion.Or(mVisibleAboveRegion, aAbove);
   301       mVisibleAboveRegion.SimplifyOutward(4);
   302     }
   303   }
   305   void CopyAboveRegion(ThebesLayerData* aOther)
   306   {
   307     if (aOther->mAllDrawingAbove || mAllDrawingAbove) {
   308       SetAllDrawingAbove();
   309     } else {
   310       mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleAboveRegion);
   311       mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleRegion);
   312       mVisibleAboveRegion.SimplifyOutward(4);
   313       mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawAboveRegion);
   314       mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawRegion);
   315       mDrawAboveRegion.SimplifyOutward(4);
   316    }
   317   }
   319   void SetAllDrawingAbove()
   320   {
   321     mAllDrawingAbove = true;
   322     mDrawAboveRegion.SetEmpty();
   323     mVisibleAboveRegion.SetEmpty();
   324   }
   326   bool DrawAboveRegionIntersects(const nsIntRect& aRect)
   327   {
   328     return mAllDrawingAbove || mDrawAboveRegion.Intersects(aRect);
   329   }
   331   bool DrawRegionIntersects(const nsIntRect& aRect)
   332   {
   333     return IsSubjectToAsyncTransforms() || mDrawRegion.Intersects(aRect);
   334   }
   336   bool IntersectsVisibleAboveRegion(const nsIntRegion& aVisibleRegion)
   337   {
   338     if (mAllDrawingAbove) {
   339       return true;
   340     }
   341     nsIntRegion visibleAboveIntersection;
   342     visibleAboveIntersection.And(mVisibleAboveRegion, aVisibleRegion);
   343     if (visibleAboveIntersection.IsEmpty()) {
   344       return false;
   345     }
   346     return true;
   347   }
   349   bool IsSubjectToAsyncTransforms()
   350   {
   351     return mFixedPosFrameForLayerData != nullptr;
   352   }
   354   /**
   355    * The region of visible content in the layer, relative to the
   356    * container layer (which is at the snapped top-left of the display
   357    * list reference frame).
   358    */
   359   nsIntRegion  mVisibleRegion;
   360   /**
   361    * The region containing the bounds of all display items in the layer,
   362    * regardless of visbility.
   363    * Same coordinate system as mVisibleRegion.
   364    * This is a conservative approximation: it contains the true region.
   365    */
   366   nsIntRegion  mDrawRegion;
   367   /**
   368    * The region of visible content in the layer that is opaque.
   369    * Same coordinate system as mVisibleRegion.
   370    */
   371   nsIntRegion  mOpaqueRegion;
   372   /**
   373    * The definitely-hit region for this ThebesLayer.
   374    */
   375   nsIntRegion  mHitRegion;
   376   /**
   377    * The maybe-hit region for this ThebesLayer.
   378    */
   379   nsIntRegion  mMaybeHitRegion;
   380   /**
   381    * The dispatch-to-content hit region for this ThebesLayer.
   382    */
   383   nsIntRegion  mDispatchToContentHitRegion;
   384   /**
   385    * The "active scrolled root" for all content in the layer. Must
   386    * be non-null; all content in a ThebesLayer must have the same
   387    * active scrolled root.
   388    */
   389   const nsIFrame* mAnimatedGeometryRoot;
   390   /**
   391    * If non-null, the frame from which we'll extract "fixed positioning"
   392    * metadata for this layer. This can be a position:fixed frame or a viewport
   393    * frame; the latter case is used for background-attachment:fixed content.
   394    */
   395   const nsIFrame* mFixedPosFrameForLayerData;
   396   const nsIFrame* mReferenceFrame;
   397   ThebesLayer* mLayer;
   398   /**
   399    * If mIsSolidColorInVisibleRegion is true, this is the color of the visible
   400    * region.
   401    */
   402   nscolor      mSolidColor;
   403   /**
   404    * True if every pixel in mVisibleRegion will have color mSolidColor.
   405    */
   406   bool mIsSolidColorInVisibleRegion;
   407   /**
   408    * True if the layer contains exactly one item that returned true for
   409    * ShouldFixToViewport.
   410    */
   411   bool mSingleItemFixedToViewport;
   412   /**
   413    * True if there is any text visible in the layer that's over
   414    * transparent pixels in the layer.
   415    */
   416   bool mNeedComponentAlpha;
   417   /**
   418    * Set if the layer should be treated as transparent, even if its entire
   419    * area is covered by opaque display items. For example, this needs to
   420    * be set if something is going to "punch holes" in the layer by clearing
   421    * part of its surface.
   422    */
   423   bool mForceTransparentSurface;
   425   /**
   426    * Stores the pointer to the nsDisplayImage if we want to
   427    * convert this to an ImageLayer.
   428    */
   429   nsDisplayImageContainer* mImage;
   430   /**
   431    * Stores the clip that we need to apply to the image or, if there is no
   432    * image, a clip for SOME item in the layer. There is no guarantee which
   433    * item's clip will be stored here and mItemClip should not be used to clip
   434    * the whole layer - only some part of the clip should be used, as determined
   435    * by ThebesDisplayItemLayerUserData::GetCommonClipCount() - which may even be
   436    * no part at all.
   437    */
   438   DisplayItemClip mItemClip;
   439   /**
   440    * The first mCommonClipCount rounded rectangle clips are identical for
   441    * all items in the layer.
   442    * -1 if there are no items in the layer; must be >=0 by the time that this
   443    * data is popped from the stack.
   444    */
   445   int32_t mCommonClipCount;
   446   /*
   447    * Updates mCommonClipCount by checking for rounded rect clips in common
   448    * between the clip on a new item (aCurrentClip) and the common clips
   449    * on items already in the layer (the first mCommonClipCount rounded rects
   450    * in mItemClip).
   451    */
   452   void UpdateCommonClipCount(const DisplayItemClip& aCurrentClip);
   454 private:
   455   /**
   456    * The region of visible content above the layer and below the
   457    * next ThebesLayerData currently in the stack, if any. Note that not
   458    * all ThebesLayers for the container are in the ThebesLayerData stack.
   459    * Same coordinate system as mVisibleRegion.
   460    * This is a conservative approximation: it contains the true region.
   461    */
   462   nsIntRegion  mVisibleAboveRegion;
   463   /**
   464    * The region containing the bounds of all display items (regardless
   465    * of visibility) in the layer and below the next ThebesLayerData
   466    * currently in the stack, if any.
   467    * Note that not all ThebesLayers for the container are in the
   468    * ThebesLayerData stack.
   469    * Same coordinate system as mVisibleRegion.
   470    */
   471   nsIntRegion  mDrawAboveRegion;
   472   /**
   473    * True if mDrawAboveRegion and mVisibleAboveRegion should be treated
   474    * as infinite, and all display items should be considered 'above' this layer.
   475    */
   476   bool mAllDrawingAbove;
   477 };
   479 /**
   480  * This is a helper object used to build up the layer children for
   481  * a ContainerLayer.
   482  */
   483 class ContainerState {
   484 public:
   485   ContainerState(nsDisplayListBuilder* aBuilder,
   486                  LayerManager* aManager,
   487                  FrameLayerBuilder* aLayerBuilder,
   488                  nsIFrame* aContainerFrame,
   489                  nsDisplayItem* aContainerItem,
   490                  ContainerLayer* aContainerLayer,
   491                  const ContainerLayerParameters& aParameters) :
   492     mBuilder(aBuilder), mManager(aManager),
   493     mLayerBuilder(aLayerBuilder),
   494     mContainerFrame(aContainerFrame),
   495     mContainerLayer(aContainerLayer),
   496     mParameters(aParameters),
   497     mNextFreeRecycledThebesLayer(0)
   498   {
   499     nsPresContext* presContext = aContainerFrame->PresContext();
   500     mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   501     mContainerReferenceFrame = aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
   502       mBuilder->FindReferenceFrameFor(mContainerFrame);
   503     mContainerAnimatedGeometryRoot = aContainerItem
   504       ? nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder)
   505       : mContainerReferenceFrame;
   506     // When AllowResidualTranslation is false, display items will be drawn
   507     // scaled with a translation by integer pixels, so we know how the snapping
   508     // will work.
   509     mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
   510       !mParameters.AllowResidualTranslation();
   511     CollectOldLayers();
   512   }
   514   enum ProcessDisplayItemsFlags {
   515     NO_COMPONENT_ALPHA = 0x01,
   516   };
   518   /**
   519    * This is the method that actually walks a display list and builds
   520    * the child layers.
   521    */
   522   void ProcessDisplayItems(const nsDisplayList& aList, uint32_t aFlags);
   523   /**
   524    * This finalizes all the open ThebesLayers by popping every element off
   525    * mThebesLayerDataStack, then sets the children of the container layer
   526    * to be all the layers in mNewChildLayers in that order and removes any
   527    * layers as children of the container that aren't in mNewChildLayers.
   528    * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
   529    * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
   530    */
   531   void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData);
   533   nsRect GetChildrenBounds() { return mBounds; }
   535   nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
   537   nsIntRect ScaleToNearestPixels(const nsRect& aRect)
   538   {
   539     return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
   540                                       mAppUnitsPerDevPixel);
   541   }
   542   nsIntRegion ScaleRegionToNearestPixels(const nsRegion& aRegion)
   543   {
   544     return aRegion.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
   545                                         mAppUnitsPerDevPixel);
   546   }
   547   nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap = false)
   548   {
   549     if (aSnap && mSnappingEnabled) {
   550       return ScaleToNearestPixels(aRect);
   551     }
   552     return aRect.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
   553                                       mAppUnitsPerDevPixel);
   554   }
   555   nsIntRect ScaleToInsidePixels(const nsRect& aRect, bool aSnap = false)
   556   {
   557     if (aSnap && mSnappingEnabled) {
   558       return ScaleToNearestPixels(aRect);
   559     }
   560     return aRect.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
   561                                      mAppUnitsPerDevPixel);
   562   }
   564   nsIntRegion ScaleRegionToInsidePixels(const nsRegion& aRegion, bool aSnap = false)
   565   {
   566     if (aSnap && mSnappingEnabled) {
   567       return ScaleRegionToNearestPixels(aRegion);
   568     }
   569     return aRegion.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
   570                                         mAppUnitsPerDevPixel);
   571   }
   573   nsIntRegion ScaleRegionToOutsidePixels(const nsRegion& aRegion, bool aSnap = false)
   574   {
   575     if (aSnap && mSnappingEnabled) {
   576       return ScaleRegionToNearestPixels(aRegion);
   577     }
   578     return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
   579                                         mAppUnitsPerDevPixel);
   580   }
   582 protected:
   583   friend class ThebesLayerData;
   585   /**
   586    * Grab the next recyclable ThebesLayer, or create one if there are no
   587    * more recyclable ThebesLayers. Does any necessary invalidation of
   588    * a recycled ThebesLayer, and sets up the transform on the ThebesLayer
   589    * to account for scrolling.
   590    */
   591   already_AddRefed<ThebesLayer> CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot,
   592                                                            const nsIFrame *aReferenceFrame,
   593                                                            const nsPoint& aTopLeft);
   594   /**
   595    * Grab the next recyclable ColorLayer, or create one if there are no
   596    * more recyclable ColorLayers.
   597    */
   598   already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(ThebesLayer* aThebes);
   599   /**
   600    * Grab the next recyclable ImageLayer, or create one if there are no
   601    * more recyclable ImageLayers.
   602    */
   603   already_AddRefed<ImageLayer> CreateOrRecycleImageLayer(ThebesLayer* aThebes);
   604   /**
   605    * Grab a recyclable ImageLayer for use as a mask layer for aLayer (that is a
   606    * mask layer which has been used for aLayer before), or create one if such
   607    * a layer doesn't exist.
   608    */
   609   already_AddRefed<ImageLayer> CreateOrRecycleMaskImageLayerFor(Layer* aLayer);
   610   /**
   611    * Grabs all ThebesLayers and ColorLayers from the ContainerLayer and makes them
   612    * available for recycling.
   613    */
   614   void CollectOldLayers();
   615   /**
   616    * If aItem used to belong to a ThebesLayer, invalidates the area of
   617    * aItem in that layer. If aNewLayer is a ThebesLayer, invalidates the area of
   618    * aItem in that layer.
   619    */
   620   void InvalidateForLayerChange(nsDisplayItem* aItem,
   621                                 Layer* aNewLayer,
   622                                 const DisplayItemClip& aClip,
   623                                 const nsPoint& aTopLeft,
   624                                 nsDisplayItemGeometry *aGeometry);
   625   /**
   626    * Try to determine whether the ThebesLayer at aThebesLayerIndex
   627    * has a single opaque color behind it, over the entire bounds of its visible
   628    * region.
   629    * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
   630    */
   631   nscolor FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex);
   632   /**
   633    * Find the fixed-pos frame, if any, containing (or equal to)
   634    * aAnimatedGeometryRoot. Only return a fixed-pos frame if its viewport
   635    * has a displayport. Updates *aVisibleRegion to be the intersection of
   636    * aDrawRegion and the displayport, and updates *aIsSolidColorInVisibleRegion
   637    * (if non-null) to false if the visible region grows.
   638    * aDisplayItemFixedToViewport is true if the layer contains a single display
   639    * item which returned true for ShouldFixToViewport.
   640    * This can return the actual viewport frame for layers whose display items
   641    * are directly on the viewport (e.g. background-attachment:fixed backgrounds).
   642    */
   643   const nsIFrame* FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot,
   644                                                 bool aDisplayItemFixedToViewport);
   645   void AdjustLayerDataForFixedPositioning(const nsIFrame* aFixedPosFrame,
   646                                           const nsIntRegion& aDrawRegion,
   647                                           nsIntRegion* aVisibleRegion,
   648                                           bool* aIsSolidColorInVisibleRegion = nullptr);
   649   /**
   650    * Set fixed-pos layer metadata on aLayer according to the data for aFixedPosFrame.
   651    */
   652   void SetFixedPositionLayerData(Layer* aLayer,
   653                                  const nsIFrame* aFixedPosFrame);
   654   /**
   655    * Indicate that we are done adding items to the ThebesLayer at the top of
   656    * mThebesLayerDataStack. Set the final visible region and opaque-content
   657    * flag, and pop it off the stack.
   658    */
   659   void PopThebesLayerData();
   660   /**
   661    * Find the ThebesLayer to which we should assign the next display item.
   662    * We scan the ThebesLayerData stack to find the topmost ThebesLayer
   663    * that is compatible with the display item (i.e., has the same
   664    * active scrolled root), and that has no content from other layers above
   665    * it and intersecting the aVisibleRect.
   666    * Returns the layer, and also updates the ThebesLayerData. Will
   667    * push a new ThebesLayerData onto the stack if no suitable existing
   668    * layer is found. If we choose a ThebesLayer that's already on the
   669    * ThebesLayerData stack, later elements on the stack will be popped off.
   670    * @param aVisibleRect the area of the next display item that's visible
   671    * @param aAnimatedGeometryRoot the active scrolled root for the next
   672    * display item
   673    * @param aOpaqueRect if non-null, a region of the display item that is opaque
   674    * @param aSolidColor if non-null, indicates that every pixel in aVisibleRect
   675    * will be painted with aSolidColor by the item
   676    * @param aShouldFixToViewport if true, aAnimatedGeometryRoot is the viewport
   677    * and we will be adding fixed-pos metadata for this layer because the
   678    * display item returned true from ShouldFixToViewport.
   679    */
   680   ThebesLayerData* FindThebesLayerFor(nsDisplayItem* aItem,
   681                                       const nsIntRect& aVisibleRect,
   682                                       const nsIFrame* aAnimatedGeometryRoot,
   683                                       const nsPoint& aTopLeft,
   684                                       bool aShouldFixToViewport);
   685   ThebesLayerData* GetTopThebesLayerData()
   686   {
   687     return mThebesLayerDataStack.IsEmpty() ? nullptr
   688         : mThebesLayerDataStack[mThebesLayerDataStack.Length() - 1].get();
   689   }
   691   /* Build a mask layer to represent the clipping region. Will return null if
   692    * there is no clipping specified or a mask layer cannot be built.
   693    * Builds an ImageLayer for the appropriate backend; the mask is relative to
   694    * aLayer's visible region.
   695    * aLayer is the layer to be clipped.
   696    * aRoundedRectClipCount is used when building mask layers for ThebesLayers,
   697    * SetupMaskLayer will build a mask layer for only the first
   698    * aRoundedRectClipCount rounded rects in aClip
   699    */
   700   void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
   701                       uint32_t aRoundedRectClipCount = UINT32_MAX);
   703   bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
   704                                   const nsIFrame **aAnimatedGeometryRoot);
   706   nsDisplayListBuilder*            mBuilder;
   707   LayerManager*                    mManager;
   708   FrameLayerBuilder*               mLayerBuilder;
   709   nsIFrame*                        mContainerFrame;
   710   const nsIFrame*                  mContainerReferenceFrame;
   711   const nsIFrame*                  mContainerAnimatedGeometryRoot;
   712   ContainerLayer*                  mContainerLayer;
   713   ContainerLayerParameters         mParameters;
   714   /**
   715    * The region of ThebesLayers that should be invalidated every time
   716    * we recycle one.
   717    */
   718   nsIntRegion                      mInvalidThebesContent;
   719   nsRect                           mBounds;
   720   nsAutoTArray<nsAutoPtr<ThebesLayerData>,1>  mThebesLayerDataStack;
   721   /**
   722    * We collect the list of children in here. During ProcessDisplayItems,
   723    * the layers in this array either have mContainerLayer as their parent,
   724    * or no parent.
   725    */
   726   typedef nsAutoTArray<nsRefPtr<Layer>,1> AutoLayersArray;
   727   AutoLayersArray                  mNewChildLayers;
   728   nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers;
   729   nsDataHashtable<nsPtrHashKey<Layer>, nsRefPtr<ImageLayer> >
   730     mRecycledMaskImageLayers;
   731   uint32_t                         mNextFreeRecycledThebesLayer;
   732   nscoord                          mAppUnitsPerDevPixel;
   733   bool                             mSnappingEnabled;
   734 };
   736 class ThebesDisplayItemLayerUserData : public LayerUserData
   737 {
   738 public:
   739   ThebesDisplayItemLayerUserData() :
   740     mMaskClipCount(0),
   741     mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
   742     mXScale(1.f), mYScale(1.f),
   743     mAppUnitsPerDevPixel(0),
   744     mTranslation(0, 0),
   745     mAnimatedGeometryRootPosition(0, 0) {}
   747   /**
   748    * Record the number of clips in the Thebes layer's mask layer.
   749    * Should not be reset when the layer is recycled since it is used to track
   750    * changes in the use of mask layers.
   751    */
   752   uint32_t mMaskClipCount;
   754   /**
   755    * A color that should be painted over the bounds of the layer's visible
   756    * region before any other content is painted.
   757    */
   758   nscolor mForcedBackgroundColor;
   760   /**
   761    * The resolution scale used.
   762    */
   763   float mXScale, mYScale;
   765   /**
   766    * The appunits per dev pixel for the items in this layer.
   767    */
   768   nscoord mAppUnitsPerDevPixel;
   770   /**
   771    * The offset from the ThebesLayer's 0,0 to the
   772    * reference frame. This isn't necessarily the same as the transform
   773    * set on the ThebesLayer since we might also be applying an extra
   774    * offset specified by the parent ContainerLayer/
   775    */
   776   nsIntPoint mTranslation;
   778   /**
   779    * We try to make 0,0 of the ThebesLayer be the top-left of the
   780    * border-box of the "active scrolled root" frame (i.e. the nearest ancestor
   781    * frame for the display items that is being actively scrolled). But
   782    * we force the ThebesLayer transform to be an integer translation, and we may
   783    * have a resolution scale, so we have to snap the ThebesLayer transform, so
   784    * 0,0 may not be exactly the top-left of the active scrolled root. Here we
   785    * store the coordinates in ThebesLayer space of the top-left of the
   786    * active scrolled root.
   787    */
   788   gfxPoint mAnimatedGeometryRootPosition;
   790   nsIntRegion mRegionToInvalidate;
   792   // The offset between the active scrolled root of this layer
   793   // and the root of the container for the previous and current
   794   // paints respectively.
   795   nsPoint mLastAnimatedGeometryRootOrigin;
   796   nsPoint mAnimatedGeometryRootOrigin;
   798   nsRefPtr<ColorLayer> mColorLayer;
   799   nsRefPtr<ImageLayer> mImageLayer;
   800 };
   802 /*
   803  * User data for layers which will be used as masks.
   804  */
   805 struct MaskLayerUserData : public LayerUserData
   806 {
   807   MaskLayerUserData()
   808     : mScaleX(-1.0f)
   809     , mScaleY(-1.0f)
   810     , mAppUnitsPerDevPixel(-1)
   811   { }
   813   bool
   814   operator== (const MaskLayerUserData& aOther) const
   815   {
   816     return mRoundedClipRects == aOther.mRoundedClipRects &&
   817            mScaleX == aOther.mScaleX &&
   818            mScaleY == aOther.mScaleY &&
   819            mOffset == aOther.mOffset &&
   820            mAppUnitsPerDevPixel == aOther.mAppUnitsPerDevPixel;
   821   }
   823   nsRefPtr<const MaskLayerImageCache::MaskLayerImageKey> mImageKey;
   824   // properties of the mask layer; the mask layer may be re-used if these
   825   // remain unchanged.
   826   nsTArray<DisplayItemClip::RoundedRect> mRoundedClipRects;
   827   // scale from the masked layer which is applied to the mask
   828   float mScaleX, mScaleY;
   829   // The ContainerLayerParameters offset which is applied to the mask's transform.
   830   nsIntPoint mOffset;
   831   int32_t mAppUnitsPerDevPixel;
   832 };
   834 /**
   835  * The address of gThebesDisplayItemLayerUserData is used as the user
   836  * data key for ThebesLayers created by FrameLayerBuilder.
   837  * It identifies ThebesLayers used to draw non-layer content, which are
   838  * therefore eligible for recycling. We want display items to be able to
   839  * create their own dedicated ThebesLayers in BuildLayer, if necessary,
   840  * and we wouldn't want to accidentally recycle those.
   841  * The user data is a ThebesDisplayItemLayerUserData.
   842  */
   843 uint8_t gThebesDisplayItemLayerUserData;
   844 /**
   845  * The address of gColorLayerUserData is used as the user
   846  * data key for ColorLayers created by FrameLayerBuilder.
   847  * The user data is null.
   848  */
   849 uint8_t gColorLayerUserData;
   850 /**
   851  * The address of gImageLayerUserData is used as the user
   852  * data key for ImageLayers created by FrameLayerBuilder.
   853  * The user data is null.
   854  */
   855 uint8_t gImageLayerUserData;
   856 /**
   857  * The address of gLayerManagerUserData is used as the user
   858  * data key for retained LayerManagers managed by FrameLayerBuilder.
   859  * The user data is a LayerManagerData.
   860  */
   861 uint8_t gLayerManagerUserData;
   862 /**
   863  * The address of gMaskLayerUserData is used as the user
   864  * data key for mask layers managed by FrameLayerBuilder.
   865  * The user data is a MaskLayerUserData.
   866  */
   867 uint8_t gMaskLayerUserData;
   869 /**
   870   * Helper functions for getting user data and casting it to the correct type.
   871   * aLayer is the layer where the user data is stored.
   872   */
   873 MaskLayerUserData* GetMaskLayerUserData(Layer* aLayer)
   874 {
   875   return static_cast<MaskLayerUserData*>(aLayer->GetUserData(&gMaskLayerUserData));
   876 }
   878 ThebesDisplayItemLayerUserData* GetThebesDisplayItemLayerUserData(Layer* aLayer)
   879 {
   880   return static_cast<ThebesDisplayItemLayerUserData*>(
   881     aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
   882 }
   884 /* static */ void
   885 FrameLayerBuilder::Shutdown()
   886 {
   887   if (gMaskLayerImageCache) {
   888     delete gMaskLayerImageCache;
   889     gMaskLayerImageCache = nullptr;
   890   }
   891 }
   893 void
   894 FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
   895                         ThebesLayerData* aLayerData)
   896 {
   897   mDisplayListBuilder = aBuilder;
   898   mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext();
   899   if (mRootPresContext) {
   900     mInitialDOMGeneration = mRootPresContext->GetDOMGeneration();
   901   }
   902   mContainingThebesLayer = aLayerData;
   903   aManager->SetUserData(&gLayerManagerLayerBuilder, this);
   904 }
   906 void
   907 FrameLayerBuilder::FlashPaint(gfxContext *aContext)
   908 {
   909   float r = float(rand()) / RAND_MAX;
   910   float g = float(rand()) / RAND_MAX;
   911   float b = float(rand()) / RAND_MAX;
   912   aContext->SetColor(gfxRGBA(r, g, b, 0.4));
   913   aContext->Paint();
   914 }
   916 FrameLayerBuilder::DisplayItemData*
   917 FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey)
   918 {
   919   nsTArray<DisplayItemData*> *array =
   920     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
   921   if (array) {
   922     for (uint32_t i = 0; i < array->Length(); i++) {
   923       DisplayItemData* item = array->ElementAt(i);
   924       if (item->mDisplayItemKey == aKey &&
   925           item->mLayer->Manager() == mRetainingManager) {
   926         return item;
   927       }
   928     }
   929   }
   930   return nullptr;
   931 }
   933 nsACString&
   934 AppendToString(nsACString& s, const nsIntRect& r,
   935                const char* pfx="", const char* sfx="")
   936 {
   937   s += pfx;
   938   s += nsPrintfCString(
   939     "(x=%d, y=%d, w=%d, h=%d)",
   940     r.x, r.y, r.width, r.height);
   941   return s += sfx;
   942 }
   944 nsACString&
   945 AppendToString(nsACString& s, const nsIntRegion& r,
   946                const char* pfx="", const char* sfx="")
   947 {
   948   s += pfx;
   950   nsIntRegionRectIterator it(r);
   951   s += "< ";
   952   while (const nsIntRect* sr = it.Next()) {
   953     AppendToString(s, *sr) += "; ";
   954   }
   955   s += ">";
   957   return s += sfx;
   958 }
   960 /**
   961  * Invalidate aRegion in aLayer. aLayer is in the coordinate system
   962  * *after* aTranslation has been applied, so we need to
   963  * apply the inverse of that transform before calling InvalidateRegion.
   964  */
   965 static void
   966 InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsIntRegion& aRegion,
   967                               const nsIntPoint& aTranslation)
   968 {
   969   // Convert the region from the coordinates of the container layer
   970   // (relative to the snapped top-left of the display list reference frame)
   971   // to the ThebesLayer's own coordinates
   972   nsIntRegion rgn = aRegion;
   973   rgn.MoveBy(-aTranslation);
   974   aLayer->InvalidateRegion(rgn);
   975 #ifdef MOZ_DUMP_PAINTING
   976   if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
   977     nsAutoCString str;
   978     AppendToString(str, rgn);
   979     printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
   980   }
   981 #endif
   982 }
   984 static void
   985 InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsRect& aRect,
   986                               const DisplayItemClip& aClip,
   987                               const nsIntPoint& aTranslation)
   988 {
   989   ThebesDisplayItemLayerUserData* data =
   990       static_cast<ThebesDisplayItemLayerUserData*>(aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
   992   nsRect rect = aClip.ApplyNonRoundedIntersection(aRect);
   994   nsIntRect pixelRect = rect.ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel);
   995   InvalidatePostTransformRegion(aLayer, pixelRect, aTranslation);
   996 }
   999 static nsIntPoint
  1000 GetTranslationForThebesLayer(ThebesLayer* aLayer)
  1002   ThebesDisplayItemLayerUserData* data =
  1003     static_cast<ThebesDisplayItemLayerUserData*>
  1004       (aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
  1005   NS_ASSERTION(data, "Must be a tracked thebes layer!");
  1007   return data->mTranslation;
  1010 /**
  1011  * Some frames can have multiple, nested, retaining layer managers
  1012  * associated with them (normal manager, inactive managers, SVG effects).
  1013  * In these cases we store the 'outermost' LayerManager data property
  1014  * on the frame since we can walk down the chain from there.
  1016  * If one of these frames has just been destroyed, we will free the inner
  1017  * layer manager when removing the entry from mFramesWithLayers. Destroying
  1018  * the layer manager destroys the LayerManagerData and calls into
  1019  * the DisplayItemData destructor. If the inner layer manager had any
  1020  * items with the same frame, then we attempt to retrieve properties
  1021  * from the deleted frame.
  1023  * Cache the destroyed frame pointer here so we can avoid crashing in this case.
  1024  */
  1026 /* static */ void
  1027 FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame,
  1028                                                void* aPropertyValue)
  1030   sDestroyedFrame = aFrame;
  1031   nsTArray<DisplayItemData*> *array =
  1032     reinterpret_cast<nsTArray<DisplayItemData*>*>(aPropertyValue);
  1034   // Hold a reference to all the items so that they don't get
  1035   // deleted from under us.
  1036   nsTArray<nsRefPtr<DisplayItemData> > arrayCopy;
  1037   for (uint32_t i = 0; i < array->Length(); ++i) {
  1038     arrayCopy.AppendElement(array->ElementAt(i));
  1041 #ifdef DEBUG_DISPLAY_ITEM_DATA
  1042   if (array->Length()) {
  1043     LayerManagerData *rootData = array->ElementAt(0)->mParent;
  1044     while (rootData->mParent) {
  1045       rootData = rootData->mParent;
  1047     printf_stderr("Removing frame %p - dumping display data\n", aFrame);
  1048     rootData->Dump();
  1050 #endif
  1052   for (uint32_t i = 0; i < array->Length(); ++i) {
  1053     DisplayItemData* data = array->ElementAt(i);
  1055     ThebesLayer* t = data->mLayer->AsThebesLayer();
  1056     if (t) {
  1057       ThebesDisplayItemLayerUserData* thebesData =
  1058           static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
  1059       if (thebesData) {
  1060         nsRegion old = data->mGeometry->ComputeInvalidationRegion();
  1061         nsIntRegion rgn = old.ScaleToOutsidePixels(thebesData->mXScale, thebesData->mYScale, thebesData->mAppUnitsPerDevPixel);
  1062         rgn.MoveBy(-GetTranslationForThebesLayer(t));
  1063         thebesData->mRegionToInvalidate.Or(thebesData->mRegionToInvalidate, rgn);
  1064         thebesData->mRegionToInvalidate.SimplifyOutward(8);
  1068     data->mParent->mDisplayItems.RemoveEntry(data);
  1071   arrayCopy.Clear();
  1072   delete array;
  1073   sDestroyedFrame = nullptr;
  1076 void
  1077 FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager)
  1079   mRetainingManager = aManager;
  1080   LayerManagerData* data = static_cast<LayerManagerData*>
  1081     (aManager->GetUserData(&gLayerManagerUserData));
  1082   if (data) {
  1083     mInvalidateAllLayers = data->mInvalidateAllLayers;
  1084   } else {
  1085     data = new LayerManagerData(aManager);
  1086     aManager->SetUserData(&gLayerManagerUserData, data);
  1090 void
  1091 FrameLayerBuilder::StoreOptimizedLayerForFrame(nsDisplayItem* aItem, Layer* aLayer)
  1093   if (!mRetainingManager) {
  1094     return;
  1097   DisplayItemData* data = GetDisplayItemDataForManager(aItem, aLayer->Manager());
  1098   NS_ASSERTION(data, "Must have already stored data for this item!");
  1099   data->mOptLayer = aLayer;
  1102 void
  1103 FrameLayerBuilder::DidEndTransaction()
  1105   GetMaskLayerImageCache()->Sweep();
  1108 void
  1109 FrameLayerBuilder::WillEndTransaction()
  1111   if (!mRetainingManager) {
  1112     return;
  1115   // We need to save the data we'll need to support retaining.
  1116   LayerManagerData* data = static_cast<LayerManagerData*>
  1117     (mRetainingManager->GetUserData(&gLayerManagerUserData));
  1118   NS_ASSERTION(data, "Must have data!");
  1119   // Update all the frames that used to have layers.
  1120   data->mDisplayItems.EnumerateEntries(ProcessRemovedDisplayItems, this);
  1121   data->mInvalidateAllLayers = false;
  1124 /* static */ PLDHashOperator
  1125 FrameLayerBuilder::ProcessRemovedDisplayItems(nsRefPtrHashKey<DisplayItemData>* aEntry,
  1126                                               void* aUserArg)
  1128   DisplayItemData* data = aEntry->GetKey();
  1129   if (!data->mUsed) {
  1130     // This item was visible, but isn't anymore.
  1131     FrameLayerBuilder* layerBuilder = static_cast<FrameLayerBuilder*>(aUserArg);
  1133     ThebesLayer* t = data->mLayer->AsThebesLayer();
  1134     if (t) {
  1135 #ifdef MOZ_DUMP_PAINTING
  1136       if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  1137         printf_stderr("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", data->mDisplayItemKey, data->mFrameList[0], t);
  1139 #endif
  1140       InvalidatePostTransformRegion(t,
  1141                                     data->mGeometry->ComputeInvalidationRegion(),
  1142                                     data->mClip,
  1143                                     layerBuilder->GetLastPaintOffset(t));
  1145     return PL_DHASH_REMOVE;
  1148   data->mUsed = false;
  1149   data->mIsInvalid = false;
  1150   return PL_DHASH_NEXT;
  1153 /* static */ PLDHashOperator
  1154 FrameLayerBuilder::DumpDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry,
  1155                                                void* aClosure)
  1157 #ifdef DEBUG_DISPLAY_ITEM_DATA
  1158   DisplayItemData *data = aEntry->GetKey();
  1160   nsAutoCString prefix;
  1161   prefix += static_cast<const char*>(aClosure);
  1163   const char *layerState;
  1164   switch (data->mLayerState) {
  1165     case LAYER_NONE:
  1166       layerState = "LAYER_NONE"; break;
  1167     case LAYER_INACTIVE:
  1168       layerState = "LAYER_INACTIVE"; break;
  1169     case LAYER_ACTIVE:
  1170       layerState = "LAYER_ACTIVE"; break;
  1171     case LAYER_ACTIVE_FORCE:
  1172       layerState = "LAYER_ACTIVE_FORCE"; break;
  1173     case LAYER_ACTIVE_EMPTY:
  1174       layerState = "LAYER_ACTIVE_EMPTY"; break;
  1175     case LAYER_SVG_EFFECTS:
  1176       layerState = "LAYER_SVG_EFFECTS"; break;
  1178   uint32_t mask = (1 << nsDisplayItem::TYPE_BITS) - 1;
  1180   nsAutoCString str;
  1181   str += prefix;
  1182   str += nsPrintfCString("Frame %p ", data->mFrameList[0]);
  1183   str += nsDisplayItem::DisplayItemTypeName(static_cast<nsDisplayItem::Type>(data->mDisplayItemKey & mask));
  1184   if ((data->mDisplayItemKey >> nsDisplayItem::TYPE_BITS)) {
  1185     str += nsPrintfCString("(%i)", data->mDisplayItemKey >> nsDisplayItem::TYPE_BITS);
  1187   str += nsPrintfCString(", %s, Layer %p", layerState, data->mLayer.get());
  1188   if (data->mOptLayer) {
  1189     str += nsPrintfCString(", OptLayer %p", data->mOptLayer.get());
  1191   if (data->mInactiveManager) {
  1192     str += nsPrintfCString(", InactiveLayerManager %p", data->mInactiveManager.get());
  1194   str += "\n";
  1196   printf_stderr("%s", str.get());
  1198   if (data->mInactiveManager) {
  1199     prefix += "  ";
  1200     printf_stderr("%sDumping inactive layer info:\n", prefix.get());
  1201     LayerManagerData* lmd = static_cast<LayerManagerData*>
  1202       (data->mInactiveManager->GetUserData(&gLayerManagerUserData));
  1203     lmd->Dump(prefix.get());
  1205 #endif
  1206   return PL_DHASH_NEXT;
  1209 /* static */ FrameLayerBuilder::DisplayItemData*
  1210 FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem,
  1211                                                 LayerManager* aManager)
  1213   nsTArray<DisplayItemData*> *array =
  1214     reinterpret_cast<nsTArray<DisplayItemData*>*>(aItem->Frame()->Properties().Get(LayerManagerDataProperty()));
  1215   if (array) {
  1216     for (uint32_t i = 0; i < array->Length(); i++) {
  1217       DisplayItemData* item = array->ElementAt(i);
  1218       if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
  1219           item->mLayer->Manager() == aManager) {
  1220         return item;
  1224   return nullptr;
  1227 bool
  1228 FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
  1230   nsTArray<DisplayItemData*> *array =
  1231     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
  1232   if (array) {
  1233     for (uint32_t i = 0; i < array->Length(); i++) {
  1234       if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) {
  1235         return true;
  1239   return false;
  1242 void
  1243 FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
  1245   nsTArray<DisplayItemData*> *array =
  1246     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
  1247   if (!array) {
  1248     return;
  1251   for (uint32_t i = 0; i < array->Length(); i++) {
  1252     DisplayItemData* data = array->ElementAt(i);
  1253     if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO) {
  1254       aCallback(aFrame, data);
  1259 FrameLayerBuilder::DisplayItemData*
  1260 FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey)
  1262   // If we need to build a new layer tree, then just refuse to recycle
  1263   // anything.
  1264   if (!mRetainingManager || mInvalidateAllLayers)
  1265     return nullptr;
  1267   DisplayItemData *data = GetDisplayItemData(aFrame, aDisplayItemKey);
  1269   if (data && data->mLayer->Manager() == mRetainingManager) {
  1270     return data;
  1272   return nullptr;
  1275 Layer*
  1276 FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem,
  1277                                   nsDisplayItemGeometry** aOldGeometry,
  1278                                   DisplayItemClip** aOldClip,
  1279                                   nsTArray<nsIFrame*>* aChangedFrames,
  1280                                   bool *aIsInvalid)
  1282   uint32_t key = aItem->GetPerFrameKey();
  1283   nsIFrame* frame = aItem->Frame();
  1285   DisplayItemData* oldData = GetOldLayerForFrame(frame, key);
  1286   if (oldData) {
  1287     if (aOldGeometry) {
  1288       *aOldGeometry = oldData->mGeometry.get();
  1290     if (aOldClip) {
  1291       *aOldClip = &oldData->mClip;
  1293     if (aChangedFrames) {
  1294       oldData->GetFrameListChanges(aItem, *aChangedFrames);
  1296     if (aIsInvalid) {
  1297       *aIsInvalid = oldData->mIsInvalid;
  1299     return oldData->mLayer;
  1302   return nullptr;
  1305 /* static */ Layer*
  1306 FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
  1308   nsTArray<DisplayItemData*> *array =
  1309     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
  1311   if (!array) {
  1312     return nullptr;
  1315   for (uint32_t i = 0; i < array->Length(); i++) {
  1316     DisplayItemData *data = array->ElementAt(i);
  1318     if (data->mDisplayItemKey == aDisplayItemKey) {
  1319       return data->mLayer;
  1322   return nullptr;
  1325 already_AddRefed<ColorLayer>
  1326 ContainerState::CreateOrRecycleColorLayer(ThebesLayer *aThebes)
  1328   ThebesDisplayItemLayerUserData* data =
  1329       static_cast<ThebesDisplayItemLayerUserData*>(aThebes->GetUserData(&gThebesDisplayItemLayerUserData));
  1330   nsRefPtr<ColorLayer> layer = data->mColorLayer;
  1331   if (layer) {
  1332     layer->SetMaskLayer(nullptr);
  1333   } else {
  1334     // Create a new layer
  1335     layer = mManager->CreateColorLayer();
  1336     if (!layer)
  1337       return nullptr;
  1338     // Mark this layer as being used for Thebes-painting display items
  1339     data->mColorLayer = layer;
  1340     layer->SetUserData(&gColorLayerUserData, nullptr);
  1342     // Remove other layer types we might have stored for this ThebesLayer
  1343     data->mImageLayer = nullptr;
  1345   return layer.forget();
  1348 already_AddRefed<ImageLayer>
  1349 ContainerState::CreateOrRecycleImageLayer(ThebesLayer *aThebes)
  1351   ThebesDisplayItemLayerUserData* data =
  1352       static_cast<ThebesDisplayItemLayerUserData*>(aThebes->GetUserData(&gThebesDisplayItemLayerUserData));
  1353   nsRefPtr<ImageLayer> layer = data->mImageLayer;
  1354   if (layer) {
  1355     layer->SetMaskLayer(nullptr);
  1356   } else {
  1357     // Create a new layer
  1358     layer = mManager->CreateImageLayer();
  1359     if (!layer)
  1360       return nullptr;
  1361     // Mark this layer as being used for Thebes-painting display items
  1362     data->mImageLayer = layer;
  1363     layer->SetUserData(&gImageLayerUserData, nullptr);
  1365     // Remove other layer types we might have stored for this ThebesLayer
  1366     data->mColorLayer = nullptr;
  1368   return layer.forget();
  1371 already_AddRefed<ImageLayer>
  1372 ContainerState::CreateOrRecycleMaskImageLayerFor(Layer* aLayer)
  1374   nsRefPtr<ImageLayer> result = mRecycledMaskImageLayers.Get(aLayer);
  1375   if (result) {
  1376     mRecycledMaskImageLayers.Remove(aLayer);
  1377     // XXX if we use clip on mask layers, null it out here
  1378   } else {
  1379     // Create a new layer
  1380     result = mManager->CreateImageLayer();
  1381     if (!result)
  1382       return nullptr;
  1383     result->SetUserData(&gMaskLayerUserData, new MaskLayerUserData());
  1384     result->SetDisallowBigImage(true);
  1387   return result.forget();
  1390 static const double SUBPIXEL_OFFSET_EPSILON = 0.02;
  1392 /**
  1393  * This normally computes NSToIntRoundUp(aValue). However, if that would
  1394  * give a residual near 0.5 while aOldResidual is near -0.5, or
  1395  * it would give a residual near -0.5 while aOldResidual is near 0.5, then
  1396  * instead we return the integer in the other direction so that the residual
  1397  * is close to aOldResidual.
  1398  */
  1399 static int32_t
  1400 RoundToMatchResidual(double aValue, double aOldResidual)
  1402   int32_t v = NSToIntRoundUp(aValue);
  1403   double residual = aValue - v;
  1404   if (aOldResidual < 0) {
  1405     if (residual > 0 && fabs(residual - 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
  1406       // Round up instead
  1407       return int32_t(ceil(aValue));
  1409   } else if (aOldResidual > 0) {
  1410     if (residual < 0 && fabs(residual + 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) {
  1411       // Round down instead
  1412       return int32_t(floor(aValue));
  1415   return v;
  1418 static void
  1419 ResetScrollPositionForLayerPixelAlignment(const nsIFrame* aAnimatedGeometryRoot)
  1421   nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(aAnimatedGeometryRoot);
  1422   if (sf) {
  1423     sf->ResetScrollPositionForLayerPixelAlignment();
  1427 static void
  1428 InvalidateEntireThebesLayer(ThebesLayer* aLayer, const nsIFrame* aAnimatedGeometryRoot)
  1430 #ifdef MOZ_DUMP_PAINTING
  1431   if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  1432     printf_stderr("Invalidating entire layer %p\n", aLayer);
  1434 #endif
  1435   nsIntRect invalidate = aLayer->GetValidRegion().GetBounds();
  1436   aLayer->InvalidateRegion(invalidate);
  1437   aLayer->SetInvalidRectToVisibleRegion();
  1438   ResetScrollPositionForLayerPixelAlignment(aAnimatedGeometryRoot);
  1441 already_AddRefed<ThebesLayer>
  1442 ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot,
  1443                                            const nsIFrame* aReferenceFrame,
  1444                                            const nsPoint& aTopLeft)
  1446   // We need a new thebes layer
  1447   nsRefPtr<ThebesLayer> layer;
  1448   ThebesDisplayItemLayerUserData* data;
  1449 #ifndef MOZ_ANDROID_OMTC
  1450   bool didResetScrollPositionForLayerPixelAlignment = false;
  1451 #endif
  1452   if (mNextFreeRecycledThebesLayer < mRecycledThebesLayers.Length()) {
  1453     // Recycle a layer
  1454     layer = mRecycledThebesLayers[mNextFreeRecycledThebesLayer];
  1455     ++mNextFreeRecycledThebesLayer;
  1456     // Clear clip rect and mask layer so we don't accidentally stay clipped.
  1457     // We will reapply any necessary clipping.
  1458     layer->SetMaskLayer(nullptr);
  1460     data = static_cast<ThebesDisplayItemLayerUserData*>
  1461         (layer->GetUserData(&gThebesDisplayItemLayerUserData));
  1462     NS_ASSERTION(data, "Recycled ThebesLayers must have user data");
  1464     // This gets called on recycled ThebesLayers that are going to be in the
  1465     // final layer tree, so it's a convenient time to invalidate the
  1466     // content that changed where we don't know what ThebesLayer it belonged
  1467     // to, or if we need to invalidate the entire layer, we can do that.
  1468     // This needs to be done before we update the ThebesLayer to its new
  1469     // transform. See nsGfxScrollFrame::InvalidateInternal, where
  1470     // we ensure that mInvalidThebesContent is updated according to the
  1471     // scroll position as of the most recent paint.
  1472     if (!FuzzyEqual(data->mXScale, mParameters.mXScale, 0.00001f) ||
  1473         !FuzzyEqual(data->mYScale, mParameters.mYScale, 0.00001f) ||
  1474         data->mAppUnitsPerDevPixel != mAppUnitsPerDevPixel) {
  1475       InvalidateEntireThebesLayer(layer, aAnimatedGeometryRoot);
  1476 #ifndef MOZ_ANDROID_OMTC
  1477       didResetScrollPositionForLayerPixelAlignment = true;
  1478 #endif
  1480     if (!data->mRegionToInvalidate.IsEmpty()) {
  1481 #ifdef MOZ_DUMP_PAINTING
  1482       if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  1483         printf_stderr("Invalidating deleted frame content from layer %p\n", layer.get());
  1485 #endif
  1486       layer->InvalidateRegion(data->mRegionToInvalidate);
  1487 #ifdef MOZ_DUMP_PAINTING
  1488       if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  1489         nsAutoCString str;
  1490         AppendToString(str, data->mRegionToInvalidate);
  1491         printf_stderr("Invalidating layer %p: %s\n", layer.get(), str.get());
  1493 #endif
  1494       data->mRegionToInvalidate.SetEmpty();
  1497     // We do not need to Invalidate these areas in the widget because we
  1498     // assume the caller of InvalidateThebesLayerContents has ensured
  1499     // the area is invalidated in the widget.
  1500   } else {
  1501     // Check whether the layer will be scrollable. This is used as a hint to
  1502     // influence whether tiled layers are used or not.
  1503     bool canScroll = false;
  1504     nsIFrame* animatedGeometryRootParent = aAnimatedGeometryRoot->GetParent();
  1505     if (animatedGeometryRootParent &&
  1506         animatedGeometryRootParent->GetType() == nsGkAtoms::scrollFrame) {
  1507       canScroll = true;
  1509     // Create a new thebes layer
  1510     layer = mManager->CreateThebesLayerWithHint(canScroll ? LayerManager::SCROLLABLE :
  1511                                                             LayerManager::NONE);
  1512     if (!layer)
  1513       return nullptr;
  1514     // Mark this layer as being used for Thebes-painting display items
  1515     data = new ThebesDisplayItemLayerUserData();
  1516     layer->SetUserData(&gThebesDisplayItemLayerUserData, data);
  1517     ResetScrollPositionForLayerPixelAlignment(aAnimatedGeometryRoot);
  1518 #ifndef MOZ_ANDROID_OMTC
  1519     didResetScrollPositionForLayerPixelAlignment = true;
  1520 #endif
  1522   data->mXScale = mParameters.mXScale;
  1523   data->mYScale = mParameters.mYScale;
  1524   data->mLastAnimatedGeometryRootOrigin = data->mAnimatedGeometryRootOrigin;
  1525   data->mAnimatedGeometryRootOrigin = aTopLeft;
  1526   data->mAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
  1527   layer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation());
  1529   mLayerBuilder->SaveLastPaintOffset(layer);
  1531   // Set up transform so that 0,0 in the Thebes layer corresponds to the
  1532   // (pixel-snapped) top-left of the aAnimatedGeometryRoot.
  1533   nsPoint offset = aAnimatedGeometryRoot->GetOffsetToCrossDoc(aReferenceFrame);
  1534   nscoord appUnitsPerDevPixel = aAnimatedGeometryRoot->PresContext()->AppUnitsPerDevPixel();
  1535   gfxPoint scaledOffset(
  1536       NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel)*mParameters.mXScale,
  1537       NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel)*mParameters.mYScale);
  1538   // We call RoundToMatchResidual here so that the residual after rounding
  1539   // is close to data->mAnimatedGeometryRootPosition if possible.
  1540   nsIntPoint pixOffset(RoundToMatchResidual(scaledOffset.x, data->mAnimatedGeometryRootPosition.x),
  1541                        RoundToMatchResidual(scaledOffset.y, data->mAnimatedGeometryRootPosition.y));
  1542   data->mTranslation = pixOffset;
  1543   pixOffset += mParameters.mOffset;
  1544   Matrix matrix;
  1545   matrix.Translate(pixOffset.x, pixOffset.y);
  1546   layer->SetBaseTransform(Matrix4x4::From2D(matrix));
  1548   // FIXME: Temporary workaround for bug 681192 and bug 724786.
  1549 #ifndef MOZ_ANDROID_OMTC
  1550   // Calculate exact position of the top-left of the active scrolled root.
  1551   // This might not be 0,0 due to the snapping in ScaleToNearestPixels.
  1552   gfxPoint animatedGeometryRootTopLeft = scaledOffset - ThebesPoint(matrix.GetTranslation()) + mParameters.mOffset;
  1553   // If it has changed, then we need to invalidate the entire layer since the
  1554   // pixels in the layer buffer have the content at a (subpixel) offset
  1555   // from what we need.
  1556   if (!animatedGeometryRootTopLeft.WithinEpsilonOf(data->mAnimatedGeometryRootPosition, SUBPIXEL_OFFSET_EPSILON)) {
  1557     data->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
  1558     InvalidateEntireThebesLayer(layer, aAnimatedGeometryRoot);
  1559   } else if (didResetScrollPositionForLayerPixelAlignment) {
  1560     data->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft;
  1562 #endif
  1564   return layer.forget();
  1567 #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
  1568 /**
  1569  * Returns the appunits per dev pixel for the item's frame
  1570  */
  1571 static int32_t
  1572 AppUnitsPerDevPixel(nsDisplayItem* aItem)
  1574   // The underlying frame for zoom items is the root frame of the subdocument.
  1575   // But zoom display items report their bounds etc using the parent document's
  1576   // APD because zoom items act as a conversion layer between the two different
  1577   // APDs.
  1578   if (aItem->GetType() == nsDisplayItem::TYPE_ZOOM) {
  1579     return static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel();
  1581   return aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
  1583 #endif
  1585 /**
  1586  * Restrict the visible region of aLayer to the region that is actually visible.
  1587  * Because we only reduce the visible region here, we don't need to worry
  1588  * about whether CONTENT_OPAQUE is set; if layer was opaque in the old
  1589  * visible region, it will still be opaque in the new one.
  1590  * @param aLayerVisibleRegion the visible region of the layer, in the layer's
  1591  * coordinate space
  1592  * @param aRestrictToRect the rect to restrict the visible region to, in the
  1593  * parent's coordinate system
  1594  */
  1595 static void
  1596 SetVisibleRegionForLayer(Layer* aLayer, const nsIntRegion& aLayerVisibleRegion,
  1597                          const nsIntRect& aRestrictToRect)
  1599   gfx3DMatrix transform;
  1600   To3DMatrix(aLayer->GetTransform(), transform);
  1602   // if 'transform' is not invertible, then nothing will be displayed
  1603   // for the layer, so it doesn't really matter what we do here
  1604   gfxRect itemVisible(aRestrictToRect.x, aRestrictToRect.y,
  1605                       aRestrictToRect.width, aRestrictToRect.height);
  1606   nsIntRect childBounds = aLayerVisibleRegion.GetBounds();
  1607   gfxRect childGfxBounds(childBounds.x, childBounds.y,
  1608                          childBounds.width, childBounds.height);
  1609   gfxRect layerVisible = transform.UntransformBounds(itemVisible, childGfxBounds);
  1610   layerVisible.RoundOut();
  1612   nsIntRect visibleRect;
  1613   if (!gfxUtils::GfxRectToIntRect(layerVisible, &visibleRect)) {
  1614     aLayer->SetVisibleRegion(nsIntRegion());
  1615   } else {
  1616     nsIntRegion rgn;
  1617     rgn.And(aLayerVisibleRegion, visibleRect);
  1618     aLayer->SetVisibleRegion(rgn);
  1622 nscolor
  1623 ContainerState::FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex)
  1625   ThebesLayerData* target = mThebesLayerDataStack[aThebesLayerIndex];
  1626   for (int32_t i = aThebesLayerIndex - 1; i >= 0; --i) {
  1627     ThebesLayerData* candidate = mThebesLayerDataStack[i];
  1628     if (candidate->IntersectsVisibleAboveRegion(target->mVisibleRegion)) {
  1629       // Some non-Thebes content between target and candidate; this is
  1630       // hopeless
  1631       break;
  1634     nsIntRegion intersection;
  1635     intersection.And(candidate->mVisibleRegion, target->mVisibleRegion);
  1636     if (intersection.IsEmpty()) {
  1637       // The layer doesn't intersect our target, ignore it and move on
  1638       continue;
  1641     // The candidate intersects our target. If any layer has a solid-color
  1642     // area behind our target, this must be it. Scan its display items.
  1643     nsIntRect deviceRect = target->mVisibleRegion.GetBounds();
  1644     nsRect appUnitRect = deviceRect.ToAppUnits(mAppUnitsPerDevPixel);
  1645     appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
  1647     FrameLayerBuilder::ThebesLayerItemsEntry* entry =
  1648       mLayerBuilder->GetThebesLayerItemsEntry(candidate->mLayer);
  1649     NS_ASSERTION(entry, "Must know about this layer!");
  1650     for (int32_t j = entry->mItems.Length() - 1; j >= 0; --j) {
  1651       nsDisplayItem* item = entry->mItems[j].mItem;
  1652       bool snap;
  1653       nsRect bounds = item->GetBounds(mBuilder, &snap);
  1654       if (snap && mSnappingEnabled) {
  1655         nsIntRect snappedBounds = ScaleToNearestPixels(bounds);
  1656         if (!snappedBounds.Intersects(deviceRect))
  1657           continue;
  1659         if (!snappedBounds.Contains(deviceRect))
  1660           break;
  1662       } else {
  1663         // The layer's visible rect is already (close enough to) pixel
  1664         // aligned, so no need to round out and in here.
  1665         if (!bounds.Intersects(appUnitRect))
  1666           continue;
  1668         if (!bounds.Contains(appUnitRect))
  1669           break;
  1672       nscolor color;
  1673       if (item->IsUniform(mBuilder, &color) && NS_GET_A(color) == 255)
  1674         return color;
  1676       break;
  1678     break;
  1680   return NS_RGBA(0,0,0,0);
  1683 void
  1684 ThebesLayerData::UpdateCommonClipCount(
  1685     const DisplayItemClip& aCurrentClip)
  1687   if (mCommonClipCount >= 0) {
  1688     mCommonClipCount = mItemClip.GetCommonRoundedRectCount(aCurrentClip, mCommonClipCount);
  1689   } else {
  1690     // first item in the layer
  1691     mCommonClipCount = aCurrentClip.GetRoundedRectCount();
  1695 already_AddRefed<ImageContainer>
  1696 ThebesLayerData::CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder)
  1698   if (!mImage) {
  1699     return nullptr;
  1702   return mImage->GetContainer(mLayer->Manager(), aBuilder);
  1705 const nsIFrame*
  1706 ContainerState::FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot,
  1707                                               bool aDisplayItemFixedToViewport)
  1709   if (!mManager->IsWidgetLayerManager()) {
  1710     // Never attach any fixed-pos metadata to inactive layers, it's pointless!
  1711     return nullptr;
  1714   nsPresContext* presContext = mContainerFrame->PresContext();
  1715   nsIFrame* viewport = presContext->PresShell()->GetRootFrame();
  1717   if (viewport == aAnimatedGeometryRoot && aDisplayItemFixedToViewport &&
  1718       nsLayoutUtils::ViewportHasDisplayPort(presContext)) {
  1719     // Probably a background-attachment:fixed item
  1720     return viewport;
  1722   // Viewports with no fixed-pos frames are not relevant.
  1723   if (!viewport->GetFirstChild(nsIFrame::kFixedList)) {
  1724     return nullptr;
  1726   for (const nsIFrame* f = aAnimatedGeometryRoot; f; f = f->GetParent()) {
  1727     if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) {
  1728       return f;
  1730     if (f == mContainerReferenceFrame) {
  1731       // The metadata will go on an ancestor layer if necessary.
  1732       return nullptr;
  1735   return nullptr;
  1738 void
  1739 ContainerState::AdjustLayerDataForFixedPositioning(const nsIFrame* aFixedPosFrame,
  1740                                                    const nsIntRegion& aDrawRegion,
  1741                                                    nsIntRegion* aVisibleRegion,
  1742                                                    bool* aIsSolidColorInVisibleRegion)
  1744   if (!aFixedPosFrame) {
  1745     return;
  1748   nsRect fixedVisibleRect;
  1749   nsPresContext* presContext = aFixedPosFrame->PresContext();
  1750   nsIPresShell* presShell = presContext->PresShell();
  1751   DebugOnly<bool> hasDisplayPort =
  1752     nsLayoutUtils::ViewportHasDisplayPort(presContext, &fixedVisibleRect);
  1753   NS_ASSERTION(hasDisplayPort, "No fixed-pos layer data if there's no displayport");
  1754   // Display ports are relative to the viewport, convert it to be relative
  1755   // to our reference frame.
  1756   nsIFrame* viewport = presShell->GetRootFrame();
  1757   if (aFixedPosFrame != viewport) {
  1758     // position: fixed items are reflowed into and only drawn inside the
  1759     // viewport, or the scroll position clamping scrollport size, if one is
  1760     // set. We differentiate background-attachment: fixed items from
  1761     // position: fixed items by the fact that background-attachment: fixed
  1762     // items use the viewport as their aFixedPosFrame.
  1763     NS_ASSERTION(aFixedPosFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED,
  1764       "should be position fixed items only");
  1765     fixedVisibleRect.MoveTo(0, 0);
  1766     if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
  1767       fixedVisibleRect.SizeTo(presShell->GetScrollPositionClampingScrollPortSize());
  1768     } else {
  1769       fixedVisibleRect.SizeTo(viewport->GetSize());
  1772   fixedVisibleRect += viewport->GetOffsetToCrossDoc(mContainerReferenceFrame);
  1773   nsIntRegion newVisibleRegion;
  1774   newVisibleRegion.And(ScaleToOutsidePixels(fixedVisibleRect, false),
  1775                        aDrawRegion);
  1776   if (!aVisibleRegion->Contains(newVisibleRegion)) {
  1777     if (aIsSolidColorInVisibleRegion) {
  1778       *aIsSolidColorInVisibleRegion = false;
  1780     *aVisibleRegion = newVisibleRegion;
  1784 void
  1785 ContainerState::SetFixedPositionLayerData(Layer* aLayer,
  1786                                           const nsIFrame* aFixedPosFrame)
  1788   aLayer->SetIsFixedPosition(aFixedPosFrame != nullptr);
  1789   if (!aFixedPosFrame) {
  1790     return;
  1793   nsPresContext* presContext = aFixedPosFrame->PresContext();
  1795   const nsIFrame* viewportFrame = aFixedPosFrame->GetParent();
  1796   // anchorRect will be in the container's coordinate system (aLayer's parent layer).
  1797   // This is the same as the display items' reference frame.
  1798   nsRect anchorRect;
  1799   if (viewportFrame) {
  1800     // Fixed position frames are reflowed into the scroll-port size if one has
  1801     // been set.
  1802     if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
  1803       anchorRect.SizeTo(presContext->PresShell()->GetScrollPositionClampingScrollPortSize());
  1804     } else {
  1805       anchorRect.SizeTo(viewportFrame->GetSize());
  1807   } else {
  1808     // A display item directly attached to the viewport.
  1809     // For background-attachment:fixed items, the anchor point is always the
  1810     // top-left of the viewport currently.
  1811     viewportFrame = aFixedPosFrame;
  1813   // The anchorRect top-left is always the viewport top-left.
  1814   anchorRect.MoveTo(viewportFrame->GetOffsetToCrossDoc(mContainerReferenceFrame));
  1816   nsLayoutUtils::SetFixedPositionLayerData(aLayer,
  1817       viewportFrame, anchorRect, aFixedPosFrame, presContext, mParameters);
  1820 static gfx3DMatrix
  1821 GetTransformToRoot(Layer* aLayer)
  1823   Matrix4x4 transform = aLayer->GetTransform();
  1824   for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
  1825     transform = transform * l->GetTransform();
  1827   gfx3DMatrix result;
  1828   To3DMatrix(transform, result);
  1829   return result;
  1832 static void
  1833 AddTransformedBoundsToRegion(const nsIntRegion& aRegion,
  1834                              const gfx3DMatrix& aTransform,
  1835                              nsIntRegion* aDest)
  1837   nsIntRect bounds = aRegion.GetBounds();
  1838   gfxRect transformed =
  1839     aTransform.TransformBounds(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
  1840   transformed.RoundOut();
  1841   nsIntRect intRect;
  1842   if (!gfxUtils::GfxRectToIntRect(transformed, &intRect)) {
  1843     // This should only fail if coordinates are too big to fit in an int32
  1844     *aDest = nsIntRect(-INT32_MAX/2, -INT32_MAX/2, INT32_MAX, INT32_MAX);
  1845     return;
  1847   aDest->Or(*aDest, intRect);
  1850 static bool
  1851 CanOptimizeAwayThebesLayer(ThebesLayerData* aData,
  1852                            FrameLayerBuilder* aLayerBuilder)
  1854   bool isRetained = aData->mLayer->Manager()->IsWidgetLayerManager();
  1855   if (!isRetained) {
  1856     return false;
  1859   // If there's no thebes layer with valid content in it that we can reuse,
  1860   // always create a color or image layer (and potentially throw away an
  1861   // existing completely invalid thebes layer).
  1862   if (aData->mLayer->GetValidRegion().IsEmpty()) {
  1863     return true;
  1866   // There is an existing thebes layer we can reuse. Throwing it away can make
  1867   // compositing cheaper (see bug 946952), but it might cause us to re-allocate
  1868   // the thebes layer frequently due to an animation. So we only discard it if
  1869   // we're in tree compression mode, which is triggered at a low frequency.
  1870   return aLayerBuilder->CheckInLayerTreeCompressionMode();
  1873 void
  1874 ContainerState::PopThebesLayerData()
  1876   NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
  1878   int32_t lastIndex = mThebesLayerDataStack.Length() - 1;
  1879   ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
  1881   AdjustLayerDataForFixedPositioning(data->mFixedPosFrameForLayerData,
  1882                                      data->mDrawRegion,
  1883                                      &data->mVisibleRegion,
  1884                                      &data->mIsSolidColorInVisibleRegion);
  1885   nsRefPtr<Layer> layer;
  1886   nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder);
  1888   if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
  1889       CanOptimizeAwayThebesLayer(data, mLayerBuilder)) {
  1890     NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer),
  1891                  "Can't be a solid color as well as an image!");
  1892     if (imageContainer) {
  1893       nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer);
  1894       imageLayer->SetContainer(imageContainer);
  1895       data->mImage->ConfigureLayer(imageLayer, mParameters.mOffset);
  1896       imageLayer->SetPostScale(mParameters.mXScale,
  1897                                mParameters.mYScale);
  1898       if (data->mItemClip.HasClip()) {
  1899         nsIntRect clip = ScaleToNearestPixels(data->mItemClip.GetClipRect());
  1900         clip.MoveBy(mParameters.mOffset);
  1901         imageLayer->SetClipRect(&clip);
  1902       } else {
  1903         imageLayer->SetClipRect(nullptr);
  1905       layer = imageLayer;
  1906       mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage,
  1907                                                  imageLayer);
  1908     } else {
  1909       nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer);
  1910       colorLayer->SetColor(data->mSolidColor);
  1912       // Copy transform
  1913       colorLayer->SetBaseTransform(data->mLayer->GetBaseTransform());
  1914       colorLayer->SetPostScale(data->mLayer->GetPostXScale(), data->mLayer->GetPostYScale());
  1916       nsIntRect visibleRect = data->mVisibleRegion.GetBounds();
  1917       visibleRect.MoveBy(-GetTranslationForThebesLayer(data->mLayer));
  1918       colorLayer->SetBounds(visibleRect);
  1920       layer = colorLayer;
  1923     NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
  1924     AutoLayersArray::index_type index = mNewChildLayers.IndexOf(data->mLayer);
  1925     NS_ASSERTION(index != AutoLayersArray::NoIndex, "Thebes layer not found?");
  1926     mNewChildLayers.InsertElementAt(index + 1, layer);
  1928     // Hide the ThebesLayer. We leave it in the layer tree so that we
  1929     // can find and recycle it later.
  1930     nsIntRect emptyRect;
  1931     data->mLayer->SetClipRect(&emptyRect);
  1932     data->mLayer->SetVisibleRegion(nsIntRegion());
  1933     data->mLayer->SetEventRegions(EventRegions());
  1934   } else {
  1935     layer = data->mLayer;
  1936     imageContainer = nullptr;
  1937     layer->SetClipRect(nullptr);
  1940   Matrix transform;
  1941   if (!layer->GetTransform().Is2D(&transform)) {
  1942     NS_ERROR("Only 2D transformations currently supported");
  1945   // ImageLayers are already configured with a visible region
  1946   if (!imageContainer) {
  1947     NS_ASSERTION(!transform.HasNonIntegerTranslation(),
  1948                  "Matrix not just an integer translation?");
  1949     // Convert from relative to the container to relative to the
  1950     // ThebesLayer itself.
  1951     nsIntRegion rgn = data->mVisibleRegion;
  1952     rgn.MoveBy(-GetTranslationForThebesLayer(data->mLayer));
  1953     layer->SetVisibleRegion(rgn);
  1956   nsIntRegion transparentRegion;
  1957   transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion);
  1958   bool isOpaque = transparentRegion.IsEmpty();
  1959   // For translucent ThebesLayers, try to find an opaque background
  1960   // color that covers the entire area beneath it so we can pull that
  1961   // color into this layer to make it opaque.
  1962   if (layer == data->mLayer) {
  1963     nscolor backgroundColor = NS_RGBA(0,0,0,0);
  1964     if (!isOpaque) {
  1965       backgroundColor = FindOpaqueBackgroundColorFor(lastIndex);
  1966       if (NS_GET_A(backgroundColor) == 255) {
  1967         isOpaque = true;
  1971     // Store the background color
  1972     ThebesDisplayItemLayerUserData* userData =
  1973       GetThebesDisplayItemLayerUserData(data->mLayer);
  1974     NS_ASSERTION(userData, "where did our user data go?");
  1975     if (userData->mForcedBackgroundColor != backgroundColor) {
  1976       // Invalidate the entire target ThebesLayer since we're changing
  1977       // the background color
  1978       data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion());
  1980     userData->mForcedBackgroundColor = backgroundColor;
  1982     // use a mask layer for rounded rect clipping.
  1983     // data->mCommonClipCount may be -1 if we haven't put any actual
  1984     // drawable items in this layer (i.e. it's only catching events).
  1985     int32_t commonClipCount = std::max(0, data->mCommonClipCount);
  1986     SetupMaskLayer(layer, data->mItemClip, commonClipCount);
  1987     // copy commonClipCount to the entry
  1988     FrameLayerBuilder::ThebesLayerItemsEntry* entry = mLayerBuilder->
  1989       GetThebesLayerItemsEntry(static_cast<ThebesLayer*>(layer.get()));
  1990     entry->mCommonClipCount = commonClipCount;
  1991   } else {
  1992     // mask layer for image and color layers
  1993     SetupMaskLayer(layer, data->mItemClip);
  1996   uint32_t flags = 0;
  1997   nsIWidget* widget = mContainerReferenceFrame->PresContext()->GetRootWidget();
  1998   // See bug 941095. Not quite ready to disable this.
  1999   bool hidpi = false && widget && widget->GetDefaultScale().scale >= 2;
  2000   if (hidpi) {
  2001     flags |= Layer::CONTENT_DISABLE_SUBPIXEL_AA;
  2003   if (isOpaque && !data->mForceTransparentSurface) {
  2004     flags |= Layer::CONTENT_OPAQUE;
  2005   } else if (data->mNeedComponentAlpha && !hidpi) {
  2006     flags |= Layer::CONTENT_COMPONENT_ALPHA;
  2008   layer->SetContentFlags(flags);
  2010   SetFixedPositionLayerData(layer, data->mFixedPosFrameForLayerData);
  2012   ThebesLayerData* containingThebesLayerData =
  2013      mLayerBuilder->GetContainingThebesLayerData();
  2014   if (containingThebesLayerData) {
  2015     gfx3DMatrix matrix = GetTransformToRoot(layer);
  2016     nsIntPoint translatedDest = GetTranslationForThebesLayer(containingThebesLayerData->mLayer);
  2017     matrix.TranslatePost(-gfxPoint3D(translatedDest.x, translatedDest.y, 0));
  2018     AddTransformedBoundsToRegion(data->mDispatchToContentHitRegion, matrix,
  2019                                  &containingThebesLayerData->mDispatchToContentHitRegion);
  2020     AddTransformedBoundsToRegion(data->mMaybeHitRegion, matrix,
  2021                                  &containingThebesLayerData->mMaybeHitRegion);
  2022     // Our definitely-hit region must go to the maybe-hit-region since
  2023     // this function is an approximation.
  2024     gfxMatrix matrix2D;
  2025     bool isPrecise = matrix.Is2D(&matrix2D) && !matrix2D.HasNonAxisAlignedTransform();
  2026     AddTransformedBoundsToRegion(data->mHitRegion, matrix,
  2027       isPrecise ? &containingThebesLayerData->mHitRegion
  2028                 : &containingThebesLayerData->mMaybeHitRegion);
  2029   } else {
  2030     EventRegions regions;
  2031     regions.mHitRegion.Swap(&data->mHitRegion);
  2032     // Points whose hit-region status we're not sure about need to be dispatched
  2033     // to the content thread.
  2034     regions.mDispatchToContentHitRegion.Sub(data->mMaybeHitRegion, regions.mHitRegion);
  2035     regions.mDispatchToContentHitRegion.Or(regions.mDispatchToContentHitRegion,
  2036                                            data->mDispatchToContentHitRegion);
  2037     layer->SetEventRegions(regions);
  2040   if (lastIndex > 0) {
  2041     // Since we're going to pop off the last ThebesLayerData, the
  2042     // mVisibleAboveRegion of the second-to-last item will need to include
  2043     // the regions of the last item.
  2044     ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1];
  2045     nextData->CopyAboveRegion(data);
  2048   mThebesLayerDataStack.RemoveElementAt(lastIndex);
  2051 static bool
  2052 SuppressComponentAlpha(nsDisplayListBuilder* aBuilder,
  2053                        nsDisplayItem* aItem,
  2054                        const nsRect& aComponentAlphaBounds)
  2056   const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion();
  2057   if (!windowTransparentRegion || windowTransparentRegion->IsEmpty())
  2058     return false;
  2060   // Suppress component alpha for items in the toplevel window that are over
  2061   // the window translucent area
  2062   nsIFrame* f = aItem->Frame();
  2063   nsIFrame* ref = aBuilder->RootReferenceFrame();
  2064   if (f->PresContext() != ref->PresContext())
  2065     return false;
  2067   for (nsIFrame* t = f; t; t = t->GetParent()) {
  2068     if (t->IsTransformed())
  2069       return false;
  2072   return windowTransparentRegion->Intersects(aComponentAlphaBounds);
  2075 static bool
  2076 WindowHasTransparency(nsDisplayListBuilder* aBuilder)
  2078   const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion();
  2079   return windowTransparentRegion && !windowTransparentRegion->IsEmpty();
  2082 void
  2083 ThebesLayerData::Accumulate(ContainerState* aState,
  2084                             nsDisplayItem* aItem,
  2085                             const nsIntRect& aVisibleRect,
  2086                             const nsIntRect& aDrawRect,
  2087                             const DisplayItemClip& aClip)
  2089   if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
  2090     mForceTransparentSurface = true;
  2092   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
  2093     // Disable component alpha.
  2094     // Note that the transform (if any) on the ThebesLayer is always an integer translation so
  2095     // we don't have to factor that in here.
  2096     aItem->DisableComponentAlpha();
  2099   /* Mark as available for conversion to image layer if this is a nsDisplayImage and
  2100    * we are the first visible item in the ThebesLayerData object.
  2101    */
  2102   if (mVisibleRegion.IsEmpty() &&
  2103       aItem->SupportsOptimizingToImage()) {
  2104     mImage = static_cast<nsDisplayImageContainer*>(aItem);
  2105   } else {
  2106     mImage = nullptr;
  2108   bool clipMatches = mItemClip == aClip;
  2109   mItemClip = aClip;
  2111   if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aDrawRect) &&
  2112       mVisibleRegion.Contains(aVisibleRect)) {
  2113     // A very common case! Most pages have a ThebesLayer with the page
  2114     // background (opaque) visible and most or all of the page content over the
  2115     // top of that background.
  2116     // The rest of this method won't do anything. mVisibleRegion, mOpaqueRegion
  2117     // and mDrawRegion don't need updating. mVisibleRegion contains aVisibleRect
  2118     // already, mOpaqueRegion contains aDrawRect and therefore whatever
  2119     // the opaque region of the item is. mDrawRegion must contain mOpaqueRegion
  2120     // and therefore aDrawRect.
  2121     NS_ASSERTION(mDrawRegion.Contains(aDrawRect), "Draw region not covered");
  2122     return;
  2125   nscolor uniformColor;
  2126   bool isUniform = aItem->IsUniform(aState->mBuilder, &uniformColor);
  2128   // Some display items have to exist (so they can set forceTransparentSurface
  2129   // below) but don't draw anything. They'll return true for isUniform but
  2130   // a color with opacity 0.
  2131   if (!isUniform || NS_GET_A(uniformColor) > 0) {
  2132     // Make sure that the visible area is covered by uniform pixels. In
  2133     // particular this excludes cases where the edges of the item are not
  2134     // pixel-aligned (thus the item will not be truly uniform).
  2135     if (isUniform) {
  2136       bool snap;
  2137       nsRect bounds = aItem->GetBounds(aState->mBuilder, &snap);
  2138       if (!aState->ScaleToInsidePixels(bounds, snap).Contains(aVisibleRect)) {
  2139         isUniform = false;
  2142     if (isUniform) {
  2143       if (mVisibleRegion.IsEmpty()) {
  2144         // This color is all we have
  2145         mSolidColor = uniformColor;
  2146         mIsSolidColorInVisibleRegion = true;
  2147       } else if (mIsSolidColorInVisibleRegion &&
  2148                  mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect)) &&
  2149                  clipMatches) {
  2150         // we can just blend the colors together
  2151         mSolidColor = NS_ComposeColors(mSolidColor, uniformColor);
  2152       } else {
  2153         mIsSolidColorInVisibleRegion = false;
  2155     } else {
  2156       mIsSolidColorInVisibleRegion = false;
  2159     mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
  2160     mVisibleRegion.SimplifyOutward(4);
  2161     mDrawRegion.Or(mDrawRegion, aDrawRect);
  2162     mDrawRegion.SimplifyOutward(4);
  2165   bool snap;
  2166   nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap);
  2167   if (!opaque.IsEmpty()) {
  2168     nsRegion opaqueClipped;
  2169     nsRegionRectIterator iter(opaque);
  2170     for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
  2171       opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInward(*r));
  2174     nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap);
  2176     nsIntRegionRectIterator iter2(opaquePixels);
  2177     for (const nsIntRect* r = iter2.Next(); r; r = iter2.Next()) {
  2178       // We don't use SimplifyInward here since it's not defined exactly
  2179       // what it will discard. For our purposes the most important case
  2180       // is a large opaque background at the bottom of z-order (e.g.,
  2181       // a canvas background), so we need to make sure that the first rect
  2182       // we see doesn't get discarded.
  2183       nsIntRegion tmp;
  2184       tmp.Or(mOpaqueRegion, *r);
  2185        // Opaque display items in chrome documents whose window is partially
  2186        // transparent are always added to the opaque region. This helps ensure
  2187        // that we get as much subpixel-AA as possible in the chrome.
  2188        if (tmp.GetNumRects() <= 4 ||
  2189            (WindowHasTransparency(aState->mBuilder) &&
  2190             aItem->Frame()->PresContext()->IsChrome())) {
  2191         mOpaqueRegion = tmp;
  2196   if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
  2197     nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder);
  2198     if (!componentAlpha.IsEmpty()) {
  2199       nsIntRect componentAlphaRect =
  2200         aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect);
  2201       if (!mOpaqueRegion.Contains(componentAlphaRect)) {
  2202         if (SuppressComponentAlpha(aState->mBuilder, aItem, componentAlpha)) {
  2203           aItem->DisableComponentAlpha();
  2204         } else {
  2205           mNeedComponentAlpha = true;
  2212 ThebesLayerData*
  2213 ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
  2214                                    const nsIntRect& aVisibleRect,
  2215                                    const nsIFrame* aAnimatedGeometryRoot,
  2216                                    const nsPoint& aTopLeft,
  2217                                    bool aShouldFixToViewport)
  2219   int32_t i;
  2220   int32_t lowestUsableLayerWithScrolledRoot = -1;
  2221   int32_t topmostLayerWithScrolledRoot = -1;
  2222   for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) {
  2223     // Don't let should-fix-to-viewport items share a layer with any other items.
  2224     if (aShouldFixToViewport) {
  2225       ++i;
  2226       break;
  2228     ThebesLayerData* data = mThebesLayerDataStack[i];
  2229     // Give up if there is content drawn above (in z-order) this layer that
  2230     // intersects aItem's visible region; aItem must be placed in a
  2231     // layer this layer.
  2232     if (data->DrawAboveRegionIntersects(aVisibleRect)) {
  2233       ++i;
  2234       break;
  2236     // If the animated scrolled roots are the same and we can share this layer
  2237     // with the item, note this as a usable layer.
  2238     if (data->mAnimatedGeometryRoot == aAnimatedGeometryRoot &&
  2239         !data->mSingleItemFixedToViewport) {
  2240       lowestUsableLayerWithScrolledRoot = i;
  2241       if (topmostLayerWithScrolledRoot < 0) {
  2242         topmostLayerWithScrolledRoot = i;
  2245     // If the layer's drawn region intersects the item, stop now since no
  2246     // lower layer will be usable. Do the same if the layer is subject to
  2247     // async transforms, since we don't know where it will really be drawn.
  2248     if (data->DrawRegionIntersects(aVisibleRect))
  2249       break;
  2251   if (topmostLayerWithScrolledRoot < 0) {
  2252     --i;
  2253     for (; i >= 0; --i) {
  2254       ThebesLayerData* data = mThebesLayerDataStack[i];
  2255       if (data->mAnimatedGeometryRoot == aAnimatedGeometryRoot) {
  2256         topmostLayerWithScrolledRoot = i;
  2257         break;
  2262   if (topmostLayerWithScrolledRoot >= 0) {
  2263     while (uint32_t(topmostLayerWithScrolledRoot + 1) < mThebesLayerDataStack.Length()) {
  2264       PopThebesLayerData();
  2268   ThebesLayerData* thebesLayerData = nullptr;
  2269   if (lowestUsableLayerWithScrolledRoot < 0) {
  2270     nsRefPtr<ThebesLayer> layer =
  2271       CreateOrRecycleThebesLayer(aAnimatedGeometryRoot, aItem->ReferenceFrame(), aTopLeft);
  2273     thebesLayerData = new ThebesLayerData();
  2274     mThebesLayerDataStack.AppendElement(thebesLayerData);
  2275     thebesLayerData->mLayer = layer;
  2276     thebesLayerData->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
  2277     thebesLayerData->mFixedPosFrameForLayerData =
  2278       FindFixedPosFrameForLayerData(aAnimatedGeometryRoot, aShouldFixToViewport);
  2279     thebesLayerData->mReferenceFrame = aItem->ReferenceFrame();
  2280     thebesLayerData->mSingleItemFixedToViewport = aShouldFixToViewport;
  2282     NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???");
  2283     *mNewChildLayers.AppendElement() = layer.forget();
  2284   } else {
  2285     thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot];
  2288   return thebesLayerData;
  2291 #ifdef MOZ_DUMP_PAINTING
  2292 static void
  2293 DumpPaintedImage(nsDisplayItem* aItem, gfxASurface* aSurf)
  2295   nsCString string(aItem->Name());
  2296   string.Append("-");
  2297   string.AppendInt((uint64_t)aItem);
  2298   fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
  2299   aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
  2300   fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
  2302 #endif
  2304 static void
  2305 PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
  2306                    LayerManager* aManager,
  2307                    nsDisplayItem* aItem,
  2308                    gfxContext* aContext,
  2309                    nsRenderingContext* aCtx)
  2311   // This item has an inactive layer. Render it to a ThebesLayer
  2312   // using a temporary BasicLayerManager.
  2313   BasicLayerManager* basic = static_cast<BasicLayerManager*>(aManager);
  2314   nsRefPtr<gfxContext> context = aContext;
  2315 #ifdef MOZ_DUMP_PAINTING
  2316   int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
  2317   nsIntRect itemVisibleRect =
  2318     aItem->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel);
  2320   nsRefPtr<gfxASurface> surf;
  2321   if (gfxUtils::sDumpPainting) {
  2322     surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size().ToIntSize(),
  2323                                                               gfxContentType::COLOR_ALPHA);
  2324     surf->SetDeviceOffset(-itemVisibleRect.TopLeft());
  2325     context = new gfxContext(surf);
  2327 #endif
  2328   basic->BeginTransaction();
  2329   basic->SetTarget(context);
  2331   if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
  2332     static_cast<nsDisplaySVGEffects*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic);
  2333     if (basic->InTransaction()) {
  2334       basic->AbortTransaction();
  2336   } else {
  2337     basic->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
  2339   FrameLayerBuilder *builder = static_cast<FrameLayerBuilder*>(basic->GetUserData(&gLayerManagerLayerBuilder));
  2340   if (builder) {
  2341     builder->DidEndTransaction();
  2344   basic->SetTarget(nullptr);
  2346 #ifdef MOZ_DUMP_PAINTING
  2347   if (gfxUtils::sDumpPainting) {
  2348     DumpPaintedImage(aItem, surf);
  2350     surf->SetDeviceOffset(gfxPoint(0, 0));
  2351     aContext->SetSource(surf, itemVisibleRect.TopLeft());
  2352     aContext->Rectangle(itemVisibleRect);
  2353     aContext->Fill();
  2354     aItem->SetPainted();
  2356 #endif
  2359 /**
  2360  * Chooses a single active scrolled root for the entire display list, used
  2361  * when we are flattening layers.
  2362  */
  2363 bool
  2364 ContainerState::ChooseAnimatedGeometryRoot(const nsDisplayList& aList,
  2365                                            const nsIFrame **aAnimatedGeometryRoot)
  2367   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
  2368     LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
  2369     // Don't use an item that won't be part of any ThebesLayers to pick the
  2370     // active scrolled root.
  2371     if (layerState == LAYER_ACTIVE_FORCE) {
  2372       continue;
  2375     // Try using the actual active scrolled root of the backmost item, as that
  2376     // should result in the least invalidation when scrolling.
  2377     *aAnimatedGeometryRoot =
  2378       nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
  2379     return true;
  2381   return false;
  2384 /*
  2385  * Iterate through the non-clip items in aList and its descendants.
  2386  * For each item we compute the effective clip rect. Each item is assigned
  2387  * to a layer. We invalidate the areas in ThebesLayers where an item
  2388  * has moved from one ThebesLayer to another. Also,
  2389  * aState->mInvalidThebesContent is invalidated in every ThebesLayer.
  2390  * We set the clip rect for items that generated their own layer, and
  2391  * create a mask layer to do any rounded rect clipping.
  2392  * (ThebesLayers don't need a clip rect on the layer, we clip the items
  2393  * individually when we draw them.)
  2394  * We set the visible rect for all layers, although the actual setting
  2395  * of visible rects for some ThebesLayers is deferred until the calling
  2396  * of ContainerState::Finish.
  2397  */
  2398 void
  2399 ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
  2400                                     uint32_t aFlags)
  2402   PROFILER_LABEL("ContainerState", "ProcessDisplayItems");
  2404   const nsIFrame* lastAnimatedGeometryRoot = mContainerReferenceFrame;
  2405   nsPoint topLeft(0,0);
  2407   // When NO_COMPONENT_ALPHA is set, items will be flattened into a single
  2408   // layer, so we need to choose which active scrolled root to use for all
  2409   // items.
  2410   if (aFlags & NO_COMPONENT_ALPHA) {
  2411     if (ChooseAnimatedGeometryRoot(aList, &lastAnimatedGeometryRoot)) {
  2412       topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
  2416   int32_t maxLayers = nsDisplayItem::MaxActiveLayers();
  2417   int layerCount = 0;
  2419   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
  2420     NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
  2421       "items in a container layer should all have the same app units per dev pixel");
  2423     nsIntRect itemVisibleRect =
  2424       ScaleToOutsidePixels(item->GetVisibleRect(), false);
  2425     bool snap;
  2426     nsRect itemContent = item->GetBounds(mBuilder, &snap);
  2427     nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
  2428     nsDisplayItem::Type itemType = item->GetType();
  2429     nsIntRect clipRect;
  2430     const DisplayItemClip& itemClip = item->GetClip();
  2431     if (itemClip.HasClip()) {
  2432       itemContent.IntersectRect(itemContent, itemClip.GetClipRect());
  2433       clipRect = ScaleToNearestPixels(itemClip.GetClipRect());
  2434       itemDrawRect.IntersectRect(itemDrawRect, clipRect);
  2435       clipRect.MoveBy(mParameters.mOffset);
  2437     mBounds.UnionRect(mBounds, itemContent);
  2438     itemVisibleRect.IntersectRect(itemVisibleRect, itemDrawRect);
  2440     LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
  2441     if (layerState == LAYER_INACTIVE &&
  2442         nsDisplayItem::ForceActiveLayers()) {
  2443       layerState = LAYER_ACTIVE;
  2446     bool forceInactive;
  2447     const nsIFrame* animatedGeometryRoot;
  2448     if (aFlags & NO_COMPONENT_ALPHA) {
  2449       forceInactive = true;
  2450       animatedGeometryRoot = lastAnimatedGeometryRoot;
  2451     } else {
  2452       forceInactive = false;
  2453       if (mManager->IsWidgetLayerManager()) {
  2454         animatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
  2455       } else {
  2456         // For inactive layer subtrees, splitting content into ThebesLayers
  2457         // based on animated geometry roots is pointless. It's more efficient
  2458         // to build the minimum number of layers.
  2459         animatedGeometryRoot = mContainerAnimatedGeometryRoot;
  2461       if (animatedGeometryRoot != lastAnimatedGeometryRoot) {
  2462         lastAnimatedGeometryRoot = animatedGeometryRoot;
  2463         topLeft = animatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
  2466     bool shouldFixToViewport = !animatedGeometryRoot->GetParent() &&
  2467       item->ShouldFixToViewport(mBuilder);
  2469     if (maxLayers != -1 && layerCount >= maxLayers) {
  2470       forceInactive = true;
  2473     // Assign the item to a layer
  2474     if (layerState == LAYER_ACTIVE_FORCE ||
  2475         (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) ||
  2476         (!forceInactive &&
  2477          (layerState == LAYER_ACTIVE_EMPTY ||
  2478           layerState == LAYER_ACTIVE))) {
  2480       layerCount++;
  2482       // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
  2483       // We should never see an empty layer with any visible content!
  2484       NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
  2485                    itemVisibleRect.IsEmpty(),
  2486                    "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
  2488       // As long as the new layer isn't going to be a ThebesLayer,
  2489       // InvalidateForLayerChange doesn't need the new layer pointer.
  2490       // We also need to check the old data now, because BuildLayer
  2491       // can overwrite it.
  2492       InvalidateForLayerChange(item, nullptr, itemClip, topLeft, nullptr);
  2494       // If the item would have its own layer but is invisible, just hide it.
  2495       // Note that items without their own layers can't be skipped this
  2496       // way, since their ThebesLayer may decide it wants to draw them
  2497       // into its buffer even if they're currently covered.
  2498       if (itemVisibleRect.IsEmpty() &&
  2499           !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
  2500         continue;
  2503       if (itemType == nsDisplayItem::TYPE_TRANSFORM) {
  2504         mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr;
  2505       } else {
  2506         mParameters.mAncestorClipRect = nullptr;
  2509       // Just use its layer.
  2510       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
  2511       if (!ownLayer) {
  2512         continue;
  2515       NS_ASSERTION(!ownLayer->AsThebesLayer(),
  2516                    "Should never have created a dedicated Thebes layer!");
  2518       const nsIFrame* fixedPosFrame =
  2519         FindFixedPosFrameForLayerData(animatedGeometryRoot, shouldFixToViewport);
  2520       if (fixedPosFrame) {
  2521         nsIntRegion visibleRegion(itemVisibleRect);
  2522         AdjustLayerDataForFixedPositioning(fixedPosFrame,
  2523                                            nsIntRegion(itemDrawRect), &visibleRegion);
  2524         itemVisibleRect = visibleRegion.GetBounds();
  2526       SetFixedPositionLayerData(ownLayer, fixedPosFrame);
  2528       nsRect invalid;
  2529       if (item->IsInvalid(invalid)) {
  2530         ownLayer->SetInvalidRectToVisibleRegion();
  2533       // If it's not a ContainerLayer, we need to apply the scale transform
  2534       // ourselves.
  2535       if (!ownLayer->AsContainerLayer()) {
  2536         ownLayer->SetPostScale(mParameters.mXScale,
  2537                                mParameters.mYScale);
  2540       // Update that layer's clip and visible rects.
  2541       NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
  2542       NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
  2543                    "We shouldn't have a FrameLayerBuilder-managed layer here!");
  2544       NS_ASSERTION(itemClip.HasClip() ||
  2545                    itemClip.GetRoundedRectCount() == 0,
  2546                    "If we have rounded rects, we must have a clip rect");
  2547       // It has its own layer. Update that layer's clip and visible rects.
  2548       if (itemClip.HasClip()) {
  2549         ownLayer->SetClipRect(&clipRect);
  2550       } else {
  2551         ownLayer->SetClipRect(nullptr);
  2553       ThebesLayerData* data = GetTopThebesLayerData();
  2554       if (data) {
  2555         // Prerendered transform items can be updated without layer building
  2556         // (async animations or an empty transaction), so we treat all other
  2557         // content as being above this so that the transformed layer can correctly
  2558         // move behind other content.
  2559         if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
  2560             nsDisplayTransform::ShouldPrerenderTransformedContent(mBuilder,
  2561                                                                   item->Frame(),
  2562                                                                   false)) {
  2563           data->SetAllDrawingAbove();
  2564         } else {
  2565           data->AddVisibleAboveRegion(itemVisibleRect);
  2567           // Add the entire bounds rect to the mDrawAboveRegion.
  2568           // The visible region may be excluding opaque content above the
  2569           // item, and we need to ensure that that content is not placed
  2570           // in a ThebesLayer below the item!
  2571           data->AddDrawAboveRegion(itemDrawRect);
  2574       itemVisibleRect.MoveBy(mParameters.mOffset);
  2575       if (item->SetVisibleRegionOnLayer()) {
  2576         SetVisibleRegionForLayer(ownLayer, ownLayer->GetVisibleRegion(), itemVisibleRect);
  2579       // rounded rectangle clipping using mask layers
  2580       // (must be done after visible rect is set on layer)
  2581       if (itemClip.IsRectClippedByRoundedCorner(itemContent)) {
  2582         SetupMaskLayer(ownLayer, itemClip);
  2585       ContainerLayer* oldContainer = ownLayer->GetParent();
  2586       if (oldContainer && oldContainer != mContainerLayer) {
  2587         oldContainer->RemoveChild(ownLayer);
  2589       NS_ASSERTION(!mNewChildLayers.Contains(ownLayer),
  2590                    "Layer already in list???");
  2592       mNewChildLayers.AppendElement(ownLayer);
  2594       /**
  2595        * No need to allocate geometry for items that aren't
  2596        * part of a ThebesLayer.
  2597        */
  2598       nsAutoPtr<nsDisplayItemGeometry> dummy;
  2599       mLayerBuilder->AddLayerDisplayItem(ownLayer, item,
  2600                                          itemClip, layerState,
  2601                                          topLeft, nullptr,
  2602                                          dummy);
  2603     } else {
  2604       ThebesLayerData* data =
  2605         FindThebesLayerFor(item, itemVisibleRect, animatedGeometryRoot, topLeft,
  2606                            shouldFixToViewport);
  2608       if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
  2609         nsDisplayLayerEventRegions* eventRegions =
  2610             static_cast<nsDisplayLayerEventRegions*>(item);
  2611         data->AccumulateEventRegions(ScaleRegionToOutsidePixels(eventRegions->HitRegion()),
  2612                                      ScaleRegionToOutsidePixels(eventRegions->MaybeHitRegion()),
  2613                                      ScaleRegionToOutsidePixels(eventRegions->DispatchToContentHitRegion()));
  2614       } else {
  2615         // check to see if the new item has rounded rect clips in common with
  2616         // other items in the layer
  2617         data->UpdateCommonClipCount(itemClip);
  2618         data->Accumulate(this, item, itemVisibleRect, itemDrawRect, itemClip);
  2620         nsAutoPtr<nsDisplayItemGeometry> geometry(item->AllocateGeometry(mBuilder));
  2621         InvalidateForLayerChange(item, data->mLayer, itemClip, topLeft, geometry);
  2623         mLayerBuilder->AddThebesDisplayItem(data, item, itemClip,
  2624                                             mContainerFrame,
  2625                                             layerState, topLeft,
  2626                                             geometry);
  2632 void
  2633 ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
  2634                                          Layer* aNewLayer,
  2635                                          const DisplayItemClip& aClip,
  2636                                          const nsPoint& aTopLeft,
  2637                                          nsDisplayItemGeometry *aGeometry)
  2639   NS_ASSERTION(aItem->GetPerFrameKey(),
  2640                "Display items that render using Thebes must have a key");
  2641   nsDisplayItemGeometry *oldGeometry = nullptr;
  2642   DisplayItemClip* oldClip = nullptr;
  2643   nsAutoTArray<nsIFrame*,4> changedFrames;
  2644   bool isInvalid = false;
  2645   Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip, &changedFrames, &isInvalid);
  2646   if (aNewLayer != oldLayer && oldLayer) {
  2647     // The item has changed layers.
  2648     // Invalidate the old bounds in the old layer and new bounds in the new layer.
  2649     ThebesLayer* t = oldLayer->AsThebesLayer();
  2650     if (t) {
  2651       // Note that whenever the layer's scale changes, we invalidate the whole thing,
  2652       // so it doesn't matter whether we are using the old scale at last paint
  2653       // or a new scale here
  2654 #ifdef MOZ_DUMP_PAINTING
  2655       if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  2656         printf_stderr("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), aItem->Frame(), t, aNewLayer);
  2658 #endif
  2659       InvalidatePostTransformRegion(t,
  2660           oldGeometry->ComputeInvalidationRegion(),
  2661           *oldClip,
  2662           mLayerBuilder->GetLastPaintOffset(t));
  2664     if (aNewLayer) {
  2665       ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer();
  2666       if (newThebesLayer) {
  2667         InvalidatePostTransformRegion(newThebesLayer,
  2668             aGeometry->ComputeInvalidationRegion(),
  2669             aClip,
  2670             GetTranslationForThebesLayer(newThebesLayer));
  2673     aItem->NotifyRenderingChanged();
  2674     return;
  2676   if (!aNewLayer) {
  2677     return;
  2680   ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer();
  2681   if (!newThebesLayer) {
  2682     return;
  2685   ThebesDisplayItemLayerUserData* data =
  2686     static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData));
  2687   // If the frame is marked as invalidated, and didn't specify a rect to invalidate  then we want to
  2688   // invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas.
  2689   // If we do get an invalid rect, then we want to add this on top of the change areas.
  2690   nsRect invalid;
  2691   nsRegion combined;
  2692   nsPoint shift = aTopLeft - data->mLastAnimatedGeometryRootOrigin;
  2693   bool notifyRenderingChanged = true;
  2694   if (!oldLayer) {
  2695     // This item is being added for the first time, invalidate its entire area.
  2696     //TODO: We call GetGeometry again in AddThebesDisplayItem, we should reuse this.
  2697     combined = aClip.ApplyNonRoundedIntersection(aGeometry->ComputeInvalidationRegion());
  2698 #ifdef MOZ_DUMP_PAINTING
  2699     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  2700       printf_stderr("Display item type %s(%p) added to layer %p!\n", aItem->Name(), aItem->Frame(), aNewLayer);
  2702 #endif
  2703   } else if (isInvalid || (aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
  2704     // Either layout marked item as needing repainting, invalidate the entire old and new areas.
  2705     combined = oldClip->ApplyNonRoundedIntersection(oldGeometry->ComputeInvalidationRegion());
  2706     combined.MoveBy(shift);
  2707     combined.Or(combined, aClip.ApplyNonRoundedIntersection(aGeometry->ComputeInvalidationRegion()));
  2708 #ifdef MOZ_DUMP_PAINTING
  2709     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  2710       printf_stderr("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), aItem->Frame(), aNewLayer);
  2712 #endif
  2713   } else {
  2714     // Let the display item check for geometry changes and decide what needs to be
  2715     // repainted.
  2717     // We have an optimization to cache the drawing background-attachment: fixed canvas
  2718     // background images so we can scroll and just blit them when they are flattened into
  2719     // the same layer as scrolling content. NotifyRenderingChanged is only used to tell
  2720     // the canvas bg image item to purge this cache. We want to be careful not to accidentally
  2721     // purge the cache if we are just invalidating due to scrolling (ie the background image
  2722     // moves on the scrolling layer but it's rendering stays the same) so if
  2723     // AddOffsetAndComputeDifference is the only thing that will invalidate we skip the
  2724     // NotifyRenderingChanged call (ComputeInvalidationRegion for background images also calls
  2725     // NotifyRenderingChanged if anything changes).
  2726     if (oldGeometry->ComputeInvalidationRegion() == aGeometry->ComputeInvalidationRegion() &&
  2727         *oldClip == aClip && invalid.IsEmpty() && changedFrames.Length() == 0) {
  2728       notifyRenderingChanged = false;
  2731     oldGeometry->MoveBy(shift);
  2732     aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined);
  2733     oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(),
  2734                                            aClip, aGeometry->ComputeInvalidationRegion(),
  2735                                            &combined);
  2737     // Add in any rect that the frame specified
  2738     combined.Or(combined, invalid);
  2740     for (uint32_t i = 0; i < changedFrames.Length(); i++) {
  2741       combined.Or(combined, changedFrames[i]->GetVisualOverflowRect());
  2744     // Restrict invalidation to the clipped region
  2745     nsRegion clip;
  2746     if (aClip.ComputeRegionInClips(oldClip, shift, &clip)) {
  2747       combined.And(combined, clip);
  2749 #ifdef MOZ_DUMP_PAINTING
  2750     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  2751       if (!combined.IsEmpty()) {
  2752         printf_stderr("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), aItem->Frame(), aNewLayer);
  2755 #endif
  2757   if (!combined.IsEmpty()) {
  2758     if (notifyRenderingChanged) {
  2759       aItem->NotifyRenderingChanged();
  2761     InvalidatePostTransformRegion(newThebesLayer,
  2762         combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
  2763         GetTranslationForThebesLayer(newThebesLayer));
  2767 void
  2768 FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData,
  2769                                         nsDisplayItem* aItem,
  2770                                         const DisplayItemClip& aClip,
  2771                                         nsIFrame* aContainerLayerFrame,
  2772                                         LayerState aLayerState,
  2773                                         const nsPoint& aTopLeft,
  2774                                         nsAutoPtr<nsDisplayItemGeometry> aGeometry)
  2776   ThebesLayer* layer = aLayerData->mLayer;
  2777   ThebesDisplayItemLayerUserData* thebesData =
  2778     static_cast<ThebesDisplayItemLayerUserData*>
  2779       (layer->GetUserData(&gThebesDisplayItemLayerUserData));
  2780   nsRefPtr<BasicLayerManager> tempManager;
  2781   nsIntRect intClip;
  2782   bool hasClip = false;
  2783   if (aLayerState != LAYER_NONE) {
  2784     DisplayItemData *data = GetDisplayItemDataForManager(aItem, layer->Manager());
  2785     if (data) {
  2786       tempManager = data->mInactiveManager;
  2788     if (!tempManager) {
  2789       tempManager = new BasicLayerManager();
  2792     // We need to grab these before calling AddLayerDisplayItem because it will overwrite them.
  2793     nsRegion clip;
  2794     DisplayItemClip* oldClip = nullptr;
  2795     GetOldLayerFor(aItem, nullptr, &oldClip);
  2796     hasClip = aClip.ComputeRegionInClips(oldClip,
  2797                                          aTopLeft - thebesData->mLastAnimatedGeometryRootOrigin,
  2798                                          &clip);
  2800     if (hasClip) {
  2801       intClip = clip.GetBounds().ScaleToOutsidePixels(thebesData->mXScale,
  2802                                                       thebesData->mYScale,
  2803                                                       thebesData->mAppUnitsPerDevPixel);
  2807   AddLayerDisplayItem(layer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
  2809   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(layer);
  2810   if (entry) {
  2811     entry->mContainerLayerFrame = aContainerLayerFrame;
  2812     if (entry->mContainerLayerGeneration == 0) {
  2813       entry->mContainerLayerGeneration = mContainerLayerGeneration;
  2815     if (tempManager) {
  2816       FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
  2817       layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData);
  2819       tempManager->BeginTransaction();
  2820       if (mRetainingManager) {
  2821         layerBuilder->DidBeginRetainedLayerTransaction(tempManager);
  2824       nsAutoPtr<LayerProperties> props(LayerProperties::CloneFrom(tempManager->GetRoot()));
  2825       nsRefPtr<Layer> tmpLayer =
  2826         aItem->BuildLayer(mDisplayListBuilder, tempManager, ContainerLayerParameters());
  2827       // We have no easy way of detecting if this transaction will ever actually get finished.
  2828       // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp
  2829       if (!tmpLayer) {
  2830         tempManager->EndTransaction(nullptr, nullptr);
  2831         tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
  2832         return;
  2835       // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
  2836       // stored in layerBuilder. Manually add it now.
  2837       if (mRetainingManager) {
  2838 #ifdef DEBUG_DISPLAY_ITEM_DATA
  2839         LayerManagerData* parentLmd = static_cast<LayerManagerData*>
  2840           (layer->Manager()->GetUserData(&gLayerManagerUserData));
  2841         LayerManagerData* lmd = static_cast<LayerManagerData*>
  2842           (tempManager->GetUserData(&gLayerManagerUserData));
  2843         lmd->mParent = parentLmd;
  2844 #endif
  2845         layerBuilder->StoreDataForFrame(aItem, tmpLayer, LAYER_ACTIVE);
  2848       tempManager->SetRoot(tmpLayer);
  2849       layerBuilder->WillEndTransaction();
  2850       tempManager->AbortTransaction();
  2852       nsIntPoint offset = GetLastPaintOffset(layer) - GetTranslationForThebesLayer(layer);
  2853       props->MoveBy(-offset);
  2854       nsIntRegion invalid = props->ComputeDifferences(tmpLayer, nullptr);
  2855       if (aLayerState == LAYER_SVG_EFFECTS) {
  2856         invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(aItem->Frame(),
  2857                                                                         aItem->ToReferenceFrame(),
  2858                                                                         invalid);
  2860       if (!invalid.IsEmpty()) {
  2861 #ifdef MOZ_DUMP_PAINTING
  2862         if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  2863           printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->Frame(), layer);
  2865 #endif
  2866         if (hasClip) {
  2867           invalid.And(invalid, intClip);
  2870         invalid.ScaleRoundOut(thebesData->mXScale, thebesData->mYScale);
  2871         InvalidatePostTransformRegion(layer, invalid,
  2872                                       GetTranslationForThebesLayer(layer));
  2875     ClippedDisplayItem* cdi =
  2876       entry->mItems.AppendElement(ClippedDisplayItem(aItem,
  2877                                                      mContainerLayerGeneration));
  2878     cdi->mInactiveLayerManager = tempManager;
  2882 FrameLayerBuilder::DisplayItemData*
  2883 FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer, LayerState aState)
  2885   DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager);
  2886   if (oldData) {
  2887     if (!oldData->mUsed) {
  2888       oldData->UpdateContents(aLayer, aState, mContainerLayerGeneration, aItem);
  2890     return oldData;
  2893   LayerManagerData* lmd = static_cast<LayerManagerData*>
  2894     (mRetainingManager->GetUserData(&gLayerManagerUserData));
  2896   nsRefPtr<DisplayItemData> data =
  2897     new DisplayItemData(lmd, aItem->GetPerFrameKey(),
  2898                         aLayer, aState, mContainerLayerGeneration);
  2900   data->AddFrame(aItem->Frame());
  2902   nsAutoTArray<nsIFrame*,4> mergedFrames;
  2903   aItem->GetMergedFrames(&mergedFrames);
  2905   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
  2906     data->AddFrame(mergedFrames[i]);
  2909   lmd->mDisplayItems.PutEntry(data);
  2910   return data;
  2913 void
  2914 FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame,
  2915                                      uint32_t aDisplayItemKey,
  2916                                      Layer* aLayer,
  2917                                      LayerState aState)
  2919   DisplayItemData* oldData = GetDisplayItemData(aFrame, aDisplayItemKey);
  2920   if (oldData && oldData->mFrameList.Length() == 1) {
  2921     oldData->UpdateContents(aLayer, aState, mContainerLayerGeneration);
  2922     return;
  2925   LayerManagerData* lmd = static_cast<LayerManagerData*>
  2926     (mRetainingManager->GetUserData(&gLayerManagerUserData));
  2928   nsRefPtr<DisplayItemData> data =
  2929     new DisplayItemData(lmd, aDisplayItemKey, aLayer,
  2930                         aState, mContainerLayerGeneration);
  2932   data->AddFrame(aFrame);
  2934   lmd->mDisplayItems.PutEntry(data);
  2937 FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem()
  2939   if (mInactiveLayerManager) {
  2940     BasicLayerManager* basic = static_cast<BasicLayerManager*>(mInactiveLayerManager.get());
  2941     basic->SetUserData(&gLayerManagerLayerBuilder, nullptr);
  2945 void
  2946 FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
  2947                                        nsDisplayItem* aItem,
  2948                                        const DisplayItemClip& aClip,
  2949                                        LayerState aLayerState,
  2950                                        const nsPoint& aTopLeft,
  2951                                        BasicLayerManager* aManager,
  2952                                        nsAutoPtr<nsDisplayItemGeometry> aGeometry)
  2954   if (aLayer->Manager() != mRetainingManager)
  2955     return;
  2957   DisplayItemData *data = StoreDataForFrame(aItem, aLayer, aLayerState);
  2958   ThebesLayer *t = aLayer->AsThebesLayer();
  2959   if (t) {
  2960     data->mGeometry = aGeometry;
  2961     data->mClip = aClip;
  2963   data->mInactiveManager = aManager;
  2966 nsIntPoint
  2967 FrameLayerBuilder::GetLastPaintOffset(ThebesLayer* aLayer)
  2969   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
  2970   if (entry) {
  2971     if (entry->mContainerLayerGeneration == 0) {
  2972       entry->mContainerLayerGeneration = mContainerLayerGeneration;
  2974     if (entry->mHasExplicitLastPaintOffset)
  2975       return entry->mLastPaintOffset;
  2977   return GetTranslationForThebesLayer(aLayer);
  2980 void
  2981 FrameLayerBuilder::SaveLastPaintOffset(ThebesLayer* aLayer)
  2983   ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
  2984   if (entry) {
  2985     if (entry->mContainerLayerGeneration == 0) {
  2986       entry->mContainerLayerGeneration = mContainerLayerGeneration;
  2988     entry->mLastPaintOffset = GetTranslationForThebesLayer(aLayer);
  2989     entry->mHasExplicitLastPaintOffset = true;
  2993 bool
  2994 FrameLayerBuilder::CheckInLayerTreeCompressionMode()
  2996   if (mInLayerTreeCompressionMode) {
  2997     return true;
  3000   // If we wanted to be in layer tree compression mode, but weren't, then scheduled
  3001   // a delayed repaint where we will be.
  3002   mRootPresContext->PresShell()->GetRootFrame()->SchedulePaint(nsIFrame::PAINT_DELAYED_COMPRESS);
  3004   return false;
  3007 void
  3008 ContainerState::CollectOldLayers()
  3010   for (Layer* layer = mContainerLayer->GetFirstChild(); layer;
  3011        layer = layer->GetNextSibling()) {
  3012     NS_ASSERTION(!layer->HasUserData(&gMaskLayerUserData),
  3013                  "Mask layer in layer tree; could not be recycled.");
  3014     if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
  3015       NS_ASSERTION(layer->AsThebesLayer(), "Wrong layer type");
  3016       mRecycledThebesLayers.AppendElement(static_cast<ThebesLayer*>(layer));
  3019     if (Layer* maskLayer = layer->GetMaskLayer()) {
  3020       NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE,
  3021                    "Could not recycle mask layer, unsupported layer type.");
  3022       mRecycledMaskImageLayers.Put(layer, static_cast<ImageLayer*>(maskLayer));
  3027 void
  3028 ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData)
  3030   while (!mThebesLayerDataStack.IsEmpty()) {
  3031     PopThebesLayerData();
  3034   uint32_t textContentFlags = 0;
  3036   // Make sure that current/existing layers are added to the parent and are
  3037   // in the correct order.
  3038   Layer* layer = nullptr;
  3039   for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i) {
  3040     Layer* prevChild = i == 0 ? nullptr : mNewChildLayers[i - 1].get();
  3041     layer = mNewChildLayers[i];
  3043     if (!layer->GetVisibleRegion().IsEmpty()) {
  3044       textContentFlags |= layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA;
  3047     if (!layer->GetParent()) {
  3048       // This is not currently a child of the container, so just add it
  3049       // now.
  3050       mContainerLayer->InsertAfter(layer, prevChild);
  3051       continue;
  3054     NS_ASSERTION(layer->GetParent() == mContainerLayer,
  3055                  "Layer shouldn't be the child of some other container");
  3056     if (layer->GetPrevSibling() != prevChild) {
  3057       mContainerLayer->RepositionChild(layer, prevChild);
  3061   // Remove old layers that have become unused.
  3062   if (!layer) {
  3063     layer = mContainerLayer->GetFirstChild();
  3064   } else {
  3065     layer = layer->GetNextSibling();
  3067   while (layer) {
  3068     Layer *layerToRemove = layer;
  3069     layer = layer->GetNextSibling();
  3070     mContainerLayer->RemoveChild(layerToRemove);
  3073   *aTextContentFlags = textContentFlags;
  3076 static inline gfxSize RoundToFloatPrecision(const gfxSize& aSize)
  3078   return gfxSize(float(aSize.width), float(aSize.height));
  3081 static bool
  3082 ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
  3083                            nsDisplayListBuilder* aDisplayListBuilder,
  3084                            nsIFrame* aContainerFrame,
  3085                            const gfx3DMatrix* aTransform,
  3086                            const ContainerLayerParameters& aIncomingScale,
  3087                            ContainerLayer* aLayer,
  3088                            LayerState aState,
  3089                            ContainerLayerParameters& aOutgoingScale)
  3091   nsIntPoint offset;
  3093   gfx3DMatrix transform =
  3094     gfx3DMatrix::ScalingMatrix(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
  3095   if (aTransform) {
  3096     // aTransform is applied first, then the scale is applied to the result
  3097     transform = (*aTransform)*transform;
  3098     // Set any matrix entries close to integers to be those exact integers.
  3099     // This protects against floating-point inaccuracies causing problems
  3100     // in the checks below.
  3101     transform.NudgeToIntegers();
  3103   gfxMatrix transform2d;
  3104   if (aContainerFrame &&
  3105       (aState == LAYER_INACTIVE || aState == LAYER_SVG_EFFECTS) &&
  3106       (!aTransform || (aTransform->Is2D(&transform2d) &&
  3107                        !transform2d.HasNonTranslation()))) {
  3108     // When we have an inactive ContainerLayer, translate the container by the offset to the
  3109     // reference frame (and offset all child layers by the reverse) so that the coordinate
  3110     // space of the child layers isn't affected by scrolling.
  3111     // This gets confusing for complicated transform (since we'd have to compute the scale
  3112     // factors for the matrix), so we don't bother. Any frames that are building an nsDisplayTransform
  3113     // for a css transform would have 0,0 as their offset to the reference frame, so this doesn't
  3114     // matter.
  3115     nsPoint appUnitOffset = aDisplayListBuilder->ToReferenceFrame(aContainerFrame);
  3116     nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
  3117     offset = nsIntPoint(
  3118         NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.x, appUnitsPerDevPixel)*aIncomingScale.mXScale),
  3119         NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.y, appUnitsPerDevPixel)*aIncomingScale.mYScale));
  3121   transform = transform * gfx3DMatrix::Translation(offset.x + aIncomingScale.mOffset.x, offset.y + aIncomingScale.mOffset.y, 0);
  3123   if (transform.IsSingular()) {
  3124     return false;
  3127   bool canDraw2D = transform.CanDraw2D(&transform2d);
  3128   gfxSize scale;
  3129   // XXX Should we do something for 3D transforms?
  3130   if (canDraw2D) {
  3131     // If the container's transform is animated off main thread, fix a suitable scale size
  3132     // for animation
  3133     if (aContainerFrame->GetContent() &&
  3134         nsLayoutUtils::HasAnimationsForCompositor(
  3135           aContainerFrame->GetContent(), eCSSProperty_transform)) {
  3136       scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(aContainerFrame->GetContent());
  3137     } else {
  3138       // Scale factors are normalized to a power of 2 to reduce the number of resolution changes
  3139       scale = RoundToFloatPrecision(transform2d.ScaleFactors(true));
  3140       // For frames with a changing transform that's not just a translation,
  3141       // round scale factors up to nearest power-of-2 boundary so that we don't
  3142       // keep having to redraw the content as it scales up and down. Rounding up to nearest
  3143       // power-of-2 boundary ensures we never scale up, only down --- avoiding
  3144       // jaggies. It also ensures we never scale down by more than a factor of 2,
  3145       // avoiding bad downscaling quality.
  3146       gfxMatrix frameTransform;
  3147       if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform) &&
  3148           aTransform &&
  3149           (!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) {
  3150         // Don't clamp the scale factor when the new desired scale factor matches the old one
  3151         // or it was previously unscaled.
  3152         bool clamp = true;
  3153         Matrix oldFrameTransform2d;
  3154         if (aLayer->GetBaseTransform().Is2D(&oldFrameTransform2d)) {
  3155           gfxSize oldScale = RoundToFloatPrecision(ThebesMatrix(oldFrameTransform2d).ScaleFactors(true));
  3156           if (oldScale == scale || oldScale == gfxSize(1.0, 1.0)) {
  3157             clamp = false;
  3160         if (clamp) {
  3161           scale.width = gfxUtils::ClampToScaleFactor(scale.width);
  3162           scale.height = gfxUtils::ClampToScaleFactor(scale.height);
  3164       } else {
  3165         // XXX Do we need to move nearly-integer values to integers here?
  3168     // If the scale factors are too small, just use 1.0. The content is being
  3169     // scaled out of sight anyway.
  3170     if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
  3171       scale = gfxSize(1.0, 1.0);
  3173   } else {
  3174     scale = gfxSize(1.0, 1.0);
  3177   // Store the inverse of our resolution-scale on the layer
  3178   Matrix4x4 baseTransform;
  3179   ToMatrix4x4(transform, baseTransform);
  3180   aLayer->SetBaseTransform(baseTransform);
  3181   aLayer->SetPreScale(1.0f/float(scale.width),
  3182                       1.0f/float(scale.height));
  3183   aLayer->SetInheritedScale(aIncomingScale.mXScale,
  3184                             aIncomingScale.mYScale);
  3186   aOutgoingScale =
  3187     ContainerLayerParameters(scale.width, scale.height, -offset, aIncomingScale);
  3188   if (aTransform) {
  3189     aOutgoingScale.mInTransformedSubtree = true;
  3190     if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform)) {
  3191       aOutgoingScale.mInActiveTransformedSubtree = true;
  3194   bool isRetained = aLayer->Manager()->IsWidgetLayerManager();
  3195   if (isRetained && (!canDraw2D || transform2d.HasNonIntegerTranslation())) {
  3196     aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true;
  3198   return true;
  3201 /* static */ PLDHashOperator
  3202 FrameLayerBuilder::RestoreDisplayItemData(nsRefPtrHashKey<DisplayItemData>* aEntry, void* aUserArg)
  3204   DisplayItemData* data = aEntry->GetKey();
  3205   uint32_t *generation = static_cast<uint32_t*>(aUserArg);
  3207   if (data->mUsed && data->mContainerLayerGeneration >= *generation) {
  3208     return PL_DHASH_REMOVE;
  3211   return PL_DHASH_NEXT;
  3214 /* static */ PLDHashOperator
  3215 FrameLayerBuilder::RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry, void* aUserArg)
  3217   uint32_t *generation = static_cast<uint32_t*>(aUserArg);
  3219   if (aEntry->mContainerLayerGeneration >= *generation) {
  3220     // We can just remove these items rather than attempting to revert them
  3221     // because we're going to want to invalidate everything when transitioning
  3222     // to component alpha flattening.
  3223     return PL_DHASH_REMOVE;
  3226   for (uint32_t i = 0; i < aEntry->mItems.Length(); i++) {
  3227     if (aEntry->mItems[i].mContainerLayerGeneration >= *generation) {
  3228       aEntry->mItems.TruncateLength(i);
  3229       return PL_DHASH_NEXT;
  3233   return PL_DHASH_NEXT;
  3236 already_AddRefed<ContainerLayer>
  3237 FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
  3238                                           LayerManager* aManager,
  3239                                           nsIFrame* aContainerFrame,
  3240                                           nsDisplayItem* aContainerItem,
  3241                                           const nsDisplayList& aChildren,
  3242                                           const ContainerLayerParameters& aParameters,
  3243                                           const gfx3DMatrix* aTransform,
  3244                                           uint32_t aFlags)
  3246   uint32_t containerDisplayItemKey =
  3247     aContainerItem ? aContainerItem->GetPerFrameKey() : nsDisplayItem::TYPE_ZERO;
  3248   NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
  3249   NS_ASSERTION(!aContainerItem ||
  3250                aContainerItem->Frame() == aContainerFrame,
  3251                "Container display item must match given frame");
  3253   if (!aParameters.mXScale || !aParameters.mYScale) {
  3254     return nullptr;
  3257   nsRefPtr<ContainerLayer> containerLayer;
  3258   if (aManager == mRetainingManager) {
  3259     // Using GetOldLayerFor will search merged frames, as well as the underlying
  3260     // frame. The underlying frame can change when a page scrolls, so this
  3261     // avoids layer recreation in the situation that a new underlying frame is
  3262     // picked for a layer.
  3263     Layer* oldLayer = nullptr;
  3264     if (aContainerItem) {
  3265       oldLayer = GetOldLayerFor(aContainerItem);
  3266     } else {
  3267       DisplayItemData *data = GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey);
  3268       if (data) {
  3269         oldLayer = data->mLayer;
  3273     if (oldLayer) {
  3274       NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
  3275       if (oldLayer->HasUserData(&gThebesDisplayItemLayerUserData)) {
  3276         // The old layer for this item is actually our ThebesLayer
  3277         // because we rendered its layer into that ThebesLayer. So we
  3278         // don't actually have a retained container layer.
  3279       } else {
  3280         NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
  3281                      "Wrong layer type");
  3282         containerLayer = static_cast<ContainerLayer*>(oldLayer);
  3283         containerLayer->SetMaskLayer(nullptr);
  3287   if (!containerLayer) {
  3288     // No suitable existing layer was found.
  3289     containerLayer = aManager->CreateContainerLayer();
  3290     if (!containerLayer)
  3291       return nullptr;
  3294   LayerState state = aContainerItem ? aContainerItem->GetLayerState(aBuilder, aManager, aParameters) : LAYER_ACTIVE;
  3295   if (state == LAYER_INACTIVE &&
  3296       nsDisplayItem::ForceActiveLayers()) {
  3297     state = LAYER_ACTIVE;
  3300   if (aContainerItem && state == LAYER_ACTIVE_EMPTY) {
  3301     // Empty layers only have metadata and should never have display items. We
  3302     // early exit because later, invalidation will walk up the frame tree to
  3303     // determine which thebes layer gets invalidated. Since an empty layer
  3304     // should never have anything to paint, it should never be invalidated.
  3305     NS_ASSERTION(aChildren.IsEmpty(), "Should have no children");
  3306     return containerLayer.forget();
  3309   ContainerLayerParameters scaleParameters;
  3310   if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aTransform, aParameters,
  3311                                   containerLayer, state, scaleParameters)) {
  3312     return nullptr;
  3315   uint32_t oldGeneration = mContainerLayerGeneration;
  3316   mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
  3318   nsRefPtr<RefCountedRegion> thebesLayerInvalidRegion = nullptr;
  3319   if (mRetainingManager) {
  3320     if (aContainerItem) {
  3321       StoreDataForFrame(aContainerItem, containerLayer, LAYER_ACTIVE);
  3322     } else {
  3323       StoreDataForFrame(aContainerFrame, containerDisplayItemKey, containerLayer, LAYER_ACTIVE);
  3327   LayerManagerData* data = static_cast<LayerManagerData*>
  3328     (aManager->GetUserData(&gLayerManagerUserData));
  3330   nsRect bounds;
  3331   nsIntRect pixBounds;
  3332   int32_t appUnitsPerDevPixel;
  3333   uint32_t stateFlags = 0;
  3334   if ((aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) &&
  3335       mRetainingManager && !mRetainingManager->AreComponentAlphaLayersEnabled()) {
  3336     stateFlags = ContainerState::NO_COMPONENT_ALPHA;
  3338   uint32_t flags;
  3339   while (true) {
  3340     ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(),
  3341                          aContainerFrame, aContainerItem,
  3342                          containerLayer, scaleParameters);
  3344     state.ProcessDisplayItems(aChildren, stateFlags);
  3346     // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
  3347     // This is suboptimal ... a child could have text that's over transparent
  3348     // pixels in its own layer, but over opaque parts of previous siblings.
  3349     state.Finish(&flags, data);
  3350     bounds = state.GetChildrenBounds();
  3351     pixBounds = state.ScaleToOutsidePixels(bounds, false);
  3352     appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
  3354     if ((flags & Layer::CONTENT_COMPONENT_ALPHA) &&
  3355         mRetainingManager &&
  3356         !mRetainingManager->AreComponentAlphaLayersEnabled() &&
  3357         !stateFlags) {
  3358       // Since we don't want any component alpha layers on BasicLayers, we repeat
  3359       // the layer building process with this explicitely forced off.
  3360       // We restore the previous FrameLayerBuilder state since the first set
  3361       // of layer building will have changed it.
  3362       stateFlags = ContainerState::NO_COMPONENT_ALPHA;
  3363       data->mDisplayItems.EnumerateEntries(RestoreDisplayItemData,
  3364                                            &mContainerLayerGeneration);
  3365       mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries,
  3366                                          &mContainerLayerGeneration);
  3367       aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
  3368       continue;
  3370     break;
  3373   NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
  3374   pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y));
  3375   if (aParameters.mAncestorClipRect && !(aFlags & CONTAINER_NOT_CLIPPED_BY_ANCESTORS)) {
  3376     SetVisibleRegionForLayer(containerLayer, nsIntRegion(pixBounds),
  3377                              *aParameters.mAncestorClipRect);
  3378   } else {
  3379     containerLayer->SetVisibleRegion(pixBounds);
  3381   // Make sure that rounding the visible region out didn't add any area
  3382   // we won't paint
  3383   if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
  3384     bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
  3385     if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
  3386       // Clear CONTENT_COMPONENT_ALPHA
  3387       flags = Layer::CONTENT_OPAQUE;
  3390   containerLayer->SetContentFlags(flags);
  3392   mContainerLayerGeneration = oldGeneration;
  3393   nsPresContext::ClearNotifySubDocInvalidationData(containerLayer);
  3395   return containerLayer.forget();
  3398 Layer*
  3399 FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
  3400                                    nsDisplayItem* aItem)
  3402   Layer* layer = GetOldLayerFor(aItem);
  3403   if (!layer)
  3404     return nullptr;
  3405   if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
  3406     // This layer was created to render Thebes-rendered content for this
  3407     // display item. The display item should not use it for its own
  3408     // layer rendering.
  3409     return nullptr;
  3411   layer->SetMaskLayer(nullptr);
  3412   return layer;
  3415 /* static */ void
  3416 FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
  3418   LayerManagerData* data = static_cast<LayerManagerData*>
  3419     (aManager->GetUserData(&gLayerManagerUserData));
  3420   if (data) {
  3421     data->mInvalidateAllLayers = true;
  3425 /* static */ void
  3426 FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame)
  3428   nsTArray<DisplayItemData*> *array =
  3429     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
  3430   if (array) {
  3431     for (uint32_t i = 0; i < array->Length(); i++) {
  3432       array->ElementAt(i)->mParent->mInvalidateAllLayers = true;
  3437 /* static */
  3438 Layer*
  3439 FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey)
  3441   //TODO: This isn't completely correct, since a frame could exist as a layer
  3442   // in the normal widget manager, and as a different layer (or no layer)
  3443   // in the secondary manager
  3445   nsTArray<DisplayItemData*> *array =
  3446     reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
  3447   if (array) {
  3448     for (uint32_t i = 0; i < array->Length(); i++) {
  3449       DisplayItemData *element = array->ElementAt(i);
  3450       if (!element->mParent->mLayerManager->IsWidgetLayerManager()) {
  3451         continue;
  3453       if (element->mDisplayItemKey == aDisplayItemKey) {
  3454         if (element->mOptLayer) {
  3455           return element->mOptLayer;
  3458         Layer* layer = element->mLayer;
  3459         if (!layer->HasUserData(&gColorLayerUserData) &&
  3460             !layer->HasUserData(&gImageLayerUserData) &&
  3461             !layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
  3462           return layer;
  3467   return nullptr;
  3470 static gfxSize
  3471 PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale,
  3472                        const gfxSize& aScale)
  3474   gfx3DMatrix transform =
  3475     gfx3DMatrix::ScalingMatrix(aScale.width, aScale.height, 1.0);
  3476   if (aFrame != aAncestorWithScale) {
  3477     // aTransform is applied first, then the scale is applied to the result
  3478     transform = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestorWithScale)*transform;
  3480   gfxMatrix transform2d;
  3481   if (transform.CanDraw2D(&transform2d)) {
  3482      return transform2d.ScaleFactors(true);
  3484   return gfxSize(1.0, 1.0);
  3487 gfxSize
  3488 FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame)
  3490   nsIFrame* last;
  3491   for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
  3492     last = f;
  3494     if (nsLayoutUtils::IsPopup(f)) {
  3495       // Don't examine ancestors of a popup. It won't make sense to check
  3496       // the transform from some content inside the popup to some content
  3497       // which is an ancestor of the popup.
  3498       break;
  3501     nsTArray<DisplayItemData*> *array =
  3502       reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
  3503     if (!array) {
  3504       continue;
  3507     for (uint32_t i = 0; i < array->Length(); i++) {
  3508       Layer* layer = array->ElementAt(i)->mLayer;
  3509       ContainerLayer* container = layer->AsContainerLayer();
  3510       if (!container ||
  3511           !layer->Manager()->IsWidgetLayerManager()) {
  3512         continue;
  3514       for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
  3515         ThebesDisplayItemLayerUserData* data =
  3516             static_cast<ThebesDisplayItemLayerUserData*>
  3517               (l->GetUserData(&gThebesDisplayItemLayerUserData));
  3518         if (data) {
  3519           return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale));
  3525   return PredictScaleForContent(aFrame, last,
  3526       last->PresContext()->PresShell()->GetResolution());
  3529 #ifdef MOZ_DUMP_PAINTING
  3530 static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder)
  3532   bool snap;
  3533   nsRect appUnitBounds = aItem->GetBounds(aBuilder, &snap);
  3534   gfxRect bounds(appUnitBounds.x, appUnitBounds.y, appUnitBounds.width, appUnitBounds.height);
  3535   bounds.ScaleInverse(aDest->AppUnitsPerDevPixel());
  3537   nsRefPtr<gfxASurface> surf =
  3538     gfxPlatform::GetPlatform()->CreateOffscreenSurface(IntSize(bounds.width, bounds.height),
  3539                                                        gfxContentType::COLOR_ALPHA);
  3540   surf->SetDeviceOffset(-bounds.TopLeft());
  3541   nsRefPtr<gfxContext> context = new gfxContext(surf);
  3542   nsRefPtr<nsRenderingContext> ctx = new nsRenderingContext();
  3543   ctx->Init(aDest->DeviceContext(), context);
  3545   aItem->Paint(aBuilder, ctx);
  3546   DumpPaintedImage(aItem, surf);
  3547   aItem->SetPainted();
  3549   surf->SetDeviceOffset(gfxPoint(0, 0));
  3550   aDest->ThebesContext()->SetSource(surf, bounds.TopLeft());
  3551   aDest->ThebesContext()->Rectangle(bounds);
  3552   aDest->ThebesContext()->Fill();
  3554 #endif
  3556 /* static */ void
  3557 FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray<ClippedDisplayItem>& aItems,
  3558                                                nsDisplayListBuilder *aBuilder,
  3559                                                const nsIntRegion& aRegionToDraw,
  3560                                                const nsIntPoint& aOffset,
  3561                                                int32_t aAppUnitsPerDevPixel,
  3562                                                float aXScale,
  3563                                                float aYScale)
  3565   uint32_t i;
  3566   // Update visible regions. We need perform visibility analysis again
  3567   // because we may be asked to draw into part of a ThebesLayer that
  3568   // isn't actually visible in the window (e.g., because a ThebesLayer
  3569   // expanded its visible region to a rectangle internally), in which
  3570   // case the mVisibleRect stored in the display item may be wrong.
  3571   nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel);
  3572   visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel),
  3573                  NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel));
  3574   visible.ScaleInverseRoundOut(aXScale, aYScale);
  3576   for (i = aItems.Length(); i > 0; --i) {
  3577     ClippedDisplayItem* cdi = &aItems[i - 1];
  3578     const DisplayItemClip& clip = cdi->mItem->GetClip();
  3580     NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel,
  3581                  "a thebes layer should contain items only at the same zoom");
  3583     NS_ABORT_IF_FALSE(clip.HasClip() ||
  3584                       clip.GetRoundedRectCount() == 0,
  3585                       "If we have rounded rects, we must have a clip rect");
  3587     if (!clip.IsRectAffectedByClip(visible.GetBounds())) {
  3588       cdi->mItem->RecomputeVisibility(aBuilder, &visible);
  3589       continue;
  3592     // Do a little dance to account for the fact that we're clipping
  3593     // to cdi->mClipRect
  3594     nsRegion clipped;
  3595     clipped.And(visible, clip.NonRoundedIntersection());
  3596     nsRegion finalClipped = clipped;
  3597     cdi->mItem->RecomputeVisibility(aBuilder, &finalClipped);
  3598     // If we have rounded clip rects, don't subtract from the visible
  3599     // region since we aren't displaying everything inside the rect.
  3600     if (clip.GetRoundedRectCount() == 0) {
  3601       nsRegion removed;
  3602       removed.Sub(clipped, finalClipped);
  3603       nsRegion newVisible;
  3604       newVisible.Sub(visible, removed);
  3605       // Don't let the visible region get too complex.
  3606       if (newVisible.GetNumRects() <= 15) {
  3607         visible = newVisible;
  3613 void
  3614 FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
  3615                               const nsIntRect& aRect,
  3616                               gfxContext *aContext,
  3617                               nsRenderingContext *aRC,
  3618                               nsDisplayListBuilder* aBuilder,
  3619                               nsPresContext* aPresContext,
  3620                               const nsIntPoint& aOffset,
  3621                               float aXScale, float aYScale,
  3622                               int32_t aCommonClipCount)
  3624   int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
  3625   nsRect boundRect = aRect.ToAppUnits(appUnitsPerDevPixel);
  3626   boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
  3627                  NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
  3628   boundRect.ScaleInverseRoundOut(aXScale, aYScale);
  3630   DisplayItemClip currentClip;
  3631   bool currentClipIsSetInContext = false;
  3632   DisplayItemClip tmpClip;
  3634   for (uint32_t i = 0; i < aItems.Length(); ++i) {
  3635     ClippedDisplayItem* cdi = &aItems[i];
  3637     nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect);
  3638     if (paintRect.IsEmpty())
  3639       continue;
  3641     // If the new desired clip state is different from the current state,
  3642     // update the clip.
  3643     const DisplayItemClip* clip = &cdi->mItem->GetClip();
  3644     if (clip->GetRoundedRectCount() > 0 &&
  3645         !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
  3646       tmpClip = *clip;
  3647       tmpClip.RemoveRoundedCorners();
  3648       clip = &tmpClip;
  3650     if (currentClipIsSetInContext != clip->HasClip() ||
  3651         (clip->HasClip() && *clip != currentClip)) {
  3652       if (currentClipIsSetInContext) {
  3653         aContext->Restore();
  3655       currentClipIsSetInContext = clip->HasClip();
  3656       if (currentClipIsSetInContext) {
  3657         currentClip = *clip;
  3658         aContext->Save();
  3659         NS_ASSERTION(aCommonClipCount < 100,
  3660           "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong.");
  3661         currentClip.ApplyTo(aContext, aPresContext, aCommonClipCount);
  3662         aContext->NewPath();
  3666     if (cdi->mInactiveLayerManager) {
  3667       PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aRC);
  3668     } else {
  3669       nsIFrame* frame = cdi->mItem->Frame();
  3670       frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
  3671 #ifdef MOZ_DUMP_PAINTING
  3673       if (gfxUtils::sDumpPainting) {
  3674         DebugPaintItem(aRC, cdi->mItem, aBuilder);
  3675       } else {
  3676 #else
  3678 #endif
  3679         cdi->mItem->Paint(aBuilder, aRC);
  3683     if (CheckDOMModified())
  3684       break;
  3687   if (currentClipIsSetInContext) {
  3688     aContext->Restore();
  3692 /**
  3693  * Returns true if it is preferred to draw the list of display
  3694  * items separately for each rect in the visible region rather
  3695  * than clipping to a complex region.
  3696  */
  3697 static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
  3699   if (!gfxPrefs::LayoutPaintRectsSeparately() ||
  3700       aContext->IsCairo() ||
  3701       aClip == DrawRegionClip::CLIP_NONE) {
  3702     return false;
  3705   DrawTarget *dt = aContext->GetDrawTarget();
  3706   return dt->GetType() == BackendType::DIRECT2D;
  3709 static void DrawForcedBackgroundColor(gfxContext* aContext, Layer* aLayer, nscolor aBackgroundColor)
  3711   if (NS_GET_A(aBackgroundColor) > 0) {
  3712     nsIntRect r = aLayer->GetVisibleRegion().GetBounds();
  3713     aContext->NewPath();
  3714     aContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height));
  3715     aContext->SetColor(gfxRGBA(aBackgroundColor));
  3716     aContext->Fill();
  3720 /*
  3721  * A note on residual transforms:
  3723  * In a transformed subtree we sometimes apply the ThebesLayer's
  3724  * "residual transform" when drawing content into the ThebesLayer.
  3725  * This is a translation by components in the range [-0.5,0.5) provided
  3726  * by the layer system; applying the residual transform followed by the
  3727  * transforms used by layer compositing ensures that the subpixel alignment
  3728  * of the content of the ThebesLayer exactly matches what it would be if
  3729  * we used cairo/Thebes to draw directly to the screen without going through
  3730  * retained layer buffers.
  3732  * The visible and valid regions of the ThebesLayer are computed without
  3733  * knowing the residual transform (because we don't know what the residual
  3734  * transform is going to be until we've built the layer tree!). So we have to
  3735  * consider whether content painted in the range [x, xmost) might be painted
  3736  * outside the visible region we computed for that content. The visible region
  3737  * would be [floor(x), ceil(xmost)). The content would be rendered at
  3738  * [x + r, xmost + r), where -0.5 <= r < 0.5. So some half-rendered pixels could
  3739  * indeed fall outside the computed visible region, which is not a big deal;
  3740  * similar issues already arise when we snap cliprects to nearest pixels.
  3741  * Note that if the rendering of the content is snapped to nearest pixels ---
  3742  * which it often is --- then the content is actually rendered at
  3743  * [snap(x + r), snap(xmost + r)). It turns out that floor(x) <= snap(x + r)
  3744  * and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content
  3745  * always falls within the visible region we computed.
  3746  */
  3748 /* static */ void
  3749 FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
  3750                                    gfxContext* aContext,
  3751                                    const nsIntRegion& aRegionToDraw,
  3752                                    DrawRegionClip aClip,
  3753                                    const nsIntRegion& aRegionToInvalidate,
  3754                                    void* aCallbackData)
  3756   PROFILER_LABEL("gfx", "DrawThebesLayer");
  3758   nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*>
  3759     (aCallbackData);
  3761   FrameLayerBuilder *layerBuilder = aLayer->Manager()->GetLayerBuilder();
  3762   NS_ASSERTION(layerBuilder, "Unexpectedly null layer builder!");
  3764   if (layerBuilder->CheckDOMModified())
  3765     return;
  3767   ThebesLayerItemsEntry* entry = layerBuilder->mThebesLayerItems.GetEntry(aLayer);
  3768   NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!");
  3769   if (!entry->mContainerLayerFrame) {
  3770     return;
  3774   ThebesDisplayItemLayerUserData* userData =
  3775     static_cast<ThebesDisplayItemLayerUserData*>
  3776       (aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
  3777   NS_ASSERTION(userData, "where did our user data go?");
  3779   bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip);
  3781   if (!shouldDrawRectsSeparately) {
  3782     if (aClip == DrawRegionClip::DRAW_SNAPPED) {
  3783       gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw);
  3784     } else if (aClip == DrawRegionClip::DRAW) {
  3785       gfxUtils::ClipToRegion(aContext, aRegionToDraw);
  3788     DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
  3791   // make the origin of the context coincide with the origin of the
  3792   // ThebesLayer
  3793   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
  3794   nsIntPoint offset = GetTranslationForThebesLayer(aLayer);
  3796   nsPresContext* presContext = entry->mContainerLayerFrame->PresContext();
  3797   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
  3799   RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw,
  3800                               offset, appUnitsPerDevPixel,
  3801                               userData->mXScale, userData->mYScale);
  3803   nsRefPtr<nsRenderingContext> rc = new nsRenderingContext();
  3804   rc->Init(presContext->DeviceContext(), aContext);
  3806   if (shouldDrawRectsSeparately) {
  3807     nsIntRegionRectIterator it(aRegionToDraw);
  3808     while (const nsIntRect* iterRect = it.Next()) {
  3809       gfxContextAutoSaveRestore save(aContext);
  3810       aContext->NewPath();
  3811       aContext->Rectangle(*iterRect, aClip == DrawRegionClip::DRAW_SNAPPED);
  3812       aContext->Clip();
  3814       DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor);
  3816       // Apply the residual transform if it has been enabled, to ensure that
  3817       // snapping when we draw into aContext exactly matches the ideal transform.
  3818       // See above for why this is OK.
  3819       aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y));
  3820       aContext->Scale(userData->mXScale, userData->mYScale);
  3822       layerBuilder->PaintItems(entry->mItems, *iterRect, aContext, rc,
  3823                                builder, presContext,
  3824                                offset, userData->mXScale, userData->mYScale,
  3825                                entry->mCommonClipCount);
  3827   } else {
  3828     // Apply the residual transform if it has been enabled, to ensure that
  3829     // snapping when we draw into aContext exactly matches the ideal transform.
  3830     // See above for why this is OK.
  3831     aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y));
  3832     aContext->Scale(userData->mXScale, userData->mYScale);
  3834     layerBuilder->PaintItems(entry->mItems, aRegionToDraw.GetBounds(), aContext, rc,
  3835                              builder, presContext,
  3836                              offset, userData->mXScale, userData->mYScale,
  3837                              entry->mCommonClipCount);
  3840   if (presContext->GetPaintFlashing()) {
  3841     FlashPaint(aContext);
  3844   if (!aRegionToInvalidate.IsEmpty()) {
  3845     aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds());
  3849 bool
  3850 FrameLayerBuilder::CheckDOMModified()
  3852   if (!mRootPresContext ||
  3853       mInitialDOMGeneration == mRootPresContext->GetDOMGeneration())
  3854     return false;
  3855   if (mDetectedDOMModification) {
  3856     // Don't spam the console with extra warnings
  3857     return true;
  3859   mDetectedDOMModification = true;
  3860   // Painting is not going to complete properly. There's not much
  3861   // we can do here though. Invalidating the window to get another repaint
  3862   // is likely to lead to an infinite repaint loop.
  3863   NS_WARNING("Detected DOM modification during paint, bailing out!");
  3864   return true;
  3867 #ifdef MOZ_DUMP_PAINTING
  3868 /* static */ void
  3869 FrameLayerBuilder::DumpRetainedLayerTree(LayerManager* aManager, FILE* aFile, bool aDumpHtml)
  3871   aManager->Dump(aFile, "", aDumpHtml);
  3873 #endif
  3875 gfx::Rect
  3876 CalculateBounds(const nsTArray<DisplayItemClip::RoundedRect>& aRects, int32_t A2D)
  3878   nsRect bounds = aRects[0].mRect;
  3879   for (uint32_t i = 1; i < aRects.Length(); ++i) {
  3880     bounds.UnionRect(bounds, aRects[i].mRect);
  3883   return gfx::ToRect(nsLayoutUtils::RectToGfxRect(bounds, A2D));
  3886 static void
  3887 SetClipCount(ThebesDisplayItemLayerUserData* aThebesData,
  3888              uint32_t aClipCount)
  3890   if (aThebesData) {
  3891     aThebesData->mMaskClipCount = aClipCount;
  3895 void
  3896 ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
  3897                                uint32_t aRoundedRectClipCount)
  3899   // if the number of clips we are going to mask has decreased, then aLayer might have
  3900   // cached graphics which assume the existence of a soon-to-be non-existent mask layer
  3901   // in that case, invalidate the whole layer.
  3902   ThebesDisplayItemLayerUserData* thebesData = GetThebesDisplayItemLayerUserData(aLayer);
  3903   if (thebesData &&
  3904       aRoundedRectClipCount < thebesData->mMaskClipCount) {
  3905     ThebesLayer* thebes = aLayer->AsThebesLayer();
  3906     thebes->InvalidateRegion(thebes->GetValidRegion().GetBounds());
  3909   // don't build an unnecessary mask
  3910   nsIntRect layerBounds = aLayer->GetVisibleRegion().GetBounds();
  3911   if (aClip.GetRoundedRectCount() == 0 ||
  3912       aRoundedRectClipCount == 0 ||
  3913       layerBounds.IsEmpty()) {
  3914     SetClipCount(thebesData, 0);
  3915     return;
  3918   // check if we can re-use the mask layer
  3919   nsRefPtr<ImageLayer> maskLayer =  CreateOrRecycleMaskImageLayerFor(aLayer);
  3920   MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer);
  3922   MaskLayerUserData newData;
  3923   aClip.AppendRoundedRects(&newData.mRoundedClipRects, aRoundedRectClipCount);
  3924   newData.mScaleX = mParameters.mXScale;
  3925   newData.mScaleY = mParameters.mYScale;
  3926   newData.mOffset = mParameters.mOffset;
  3927   newData.mAppUnitsPerDevPixel = mContainerFrame->PresContext()->AppUnitsPerDevPixel();
  3929   if (*userData == newData) {
  3930     aLayer->SetMaskLayer(maskLayer);
  3931     SetClipCount(thebesData, aRoundedRectClipCount);
  3932     return;
  3935   // calculate a more precise bounding rect
  3936   gfx::Rect boundingRect = CalculateBounds(newData.mRoundedClipRects,
  3937                                            newData.mAppUnitsPerDevPixel);
  3938   boundingRect.Scale(mParameters.mXScale, mParameters.mYScale);
  3940   uint32_t maxSize = mManager->GetMaxTextureSize();
  3941   NS_ASSERTION(maxSize > 0, "Invalid max texture size");
  3942   gfx::Size surfaceSize(std::min<gfx::Float>(boundingRect.Width(), maxSize),
  3943                         std::min<gfx::Float>(boundingRect.Height(), maxSize));
  3945   // maskTransform is applied to the clip when it is painted into the mask (as a
  3946   // component of imageTransform), and its inverse used when the mask is used for
  3947   // masking.
  3948   // It is the transform from the masked layer's space to mask space
  3949   gfx::Matrix maskTransform;
  3950   maskTransform.Scale(surfaceSize.width/boundingRect.Width(),
  3951                       surfaceSize.height/boundingRect.Height());
  3952   gfx::Point p = boundingRect.TopLeft();
  3953   maskTransform.Translate(-p.x, -p.y);
  3954   // imageTransform is only used when the clip is painted to the mask
  3955   gfx::Matrix imageTransform = maskTransform;
  3956   imageTransform.Scale(mParameters.mXScale, mParameters.mYScale);
  3958   nsAutoPtr<MaskLayerImageCache::MaskLayerImageKey> newKey(
  3959     new MaskLayerImageCache::MaskLayerImageKey());
  3961   // copy and transform the rounded rects
  3962   for (uint32_t i = 0; i < newData.mRoundedClipRects.Length(); ++i) {
  3963     newKey->mRoundedClipRects.AppendElement(
  3964       MaskLayerImageCache::PixelRoundedRect(newData.mRoundedClipRects[i],
  3965                                             mContainerFrame->PresContext()));
  3966     newKey->mRoundedClipRects[i].ScaleAndTranslate(imageTransform);
  3969   const MaskLayerImageCache::MaskLayerImageKey* lookupKey = newKey;
  3971   // check to see if we can reuse a mask image
  3972   nsRefPtr<ImageContainer> container =
  3973     GetMaskLayerImageCache()->FindImageFor(&lookupKey);
  3975   if (!container) {
  3976     IntSize surfaceSizeInt(NSToIntCeil(surfaceSize.width),
  3977                            NSToIntCeil(surfaceSize.height));
  3978     // no existing mask image, so build a new one
  3979     RefPtr<DrawTarget> dt =
  3980       aLayer->Manager()->CreateOptimalMaskDrawTarget(surfaceSizeInt);
  3982     // fail if we can't get the right surface
  3983     if (!dt) {
  3984       NS_WARNING("Could not create DrawTarget for mask layer.");
  3985       SetClipCount(thebesData, 0);
  3986       return;
  3989     nsRefPtr<gfxContext> context = new gfxContext(dt);
  3990     context->Multiply(ThebesMatrix(imageTransform));
  3992     // paint the clipping rects with alpha to create the mask
  3993     context->SetColor(gfxRGBA(1, 1, 1, 1));
  3994     aClip.DrawRoundedRectsTo(context,
  3995                              newData.mAppUnitsPerDevPixel,
  3996                              0,
  3997                              aRoundedRectClipCount);
  3999     RefPtr<SourceSurface> surface = dt->Snapshot();
  4001     // build the image and container
  4002     container = aLayer->Manager()->CreateImageContainer();
  4003     NS_ASSERTION(container, "Could not create image container for mask layer.");
  4004     nsRefPtr<Image> image = container->CreateImage(ImageFormat::CAIRO_SURFACE);
  4005     NS_ASSERTION(image, "Could not create image container for mask layer.");
  4006     CairoImage::Data data;
  4007     data.mSize = surfaceSizeInt;
  4008     data.mSourceSurface = surface;
  4010     static_cast<CairoImage*>(image.get())->SetData(data);
  4011     container->SetCurrentImageInTransaction(image);
  4013     GetMaskLayerImageCache()->PutImage(newKey.forget(), container);
  4016   maskLayer->SetContainer(container);
  4018   maskTransform.Invert();
  4019   Matrix4x4 matrix = Matrix4x4::From2D(maskTransform);
  4020   matrix.Translate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
  4021   maskLayer->SetBaseTransform(matrix);
  4023   // save the details of the clip in user data
  4024   userData->mScaleX = newData.mScaleX;
  4025   userData->mScaleY = newData.mScaleY;
  4026   userData->mOffset = newData.mOffset;
  4027   userData->mAppUnitsPerDevPixel = newData.mAppUnitsPerDevPixel;
  4028   userData->mRoundedClipRects.SwapElements(newData.mRoundedClipRects);
  4029   userData->mImageKey = lookupKey;
  4031   aLayer->SetMaskLayer(maskLayer);
  4032   SetClipCount(thebesData, aRoundedRectClipCount);
  4033   return;
  4036 } // namespace mozilla

mercurial