gfx/layers/LayerTreeInvalidation.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*-*- Mode: C++; tab-width: 2; 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 file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "LayerTreeInvalidation.h"
     7 #include <stdint.h>                     // for uint32_t
     8 #include "ImageContainer.h"             // for ImageContainer
     9 #include "ImageLayers.h"                // for ImageLayer, etc
    10 #include "Layers.h"                     // for Layer, ContainerLayer, etc
    11 #include "gfx3DMatrix.h"                // for gfx3DMatrix
    12 #include "gfxColor.h"                   // for gfxRGBA
    13 #include "GraphicsFilter.h"             // for GraphicsFilter
    14 #include "gfxPoint3D.h"                 // for gfxPoint3D
    15 #include "gfxRect.h"                    // for gfxRect
    16 #include "gfxUtils.h"                   // for gfxUtils
    17 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
    18 #include "mozilla/gfx/Point.h"          // for IntSize
    19 #include "mozilla/mozalloc.h"           // for operator new, etc
    20 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr, etc
    21 #include "nsDataHashtable.h"            // for nsDataHashtable
    22 #include "nsDebug.h"                    // for NS_ASSERTION
    23 #include "nsHashKeys.h"                 // for nsPtrHashKey
    24 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
    25 #include "nsPoint.h"                    // for nsIntPoint
    26 #include "nsRect.h"                     // for nsIntRect
    27 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray_Impl
    29 namespace mozilla {
    30 namespace layers {
    32 struct LayerPropertiesBase;
    33 LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot);
    35 static nsIntRect
    36 TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform)
    37 {
    38   if (aRect.IsEmpty()) {
    39     return nsIntRect();
    40   }
    42   gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
    43   rect = aTransform.TransformBounds(rect);
    44   rect.RoundOut();
    46   nsIntRect intRect;
    47   if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) {
    48     return nsIntRect();
    49   }
    51   return intRect;
    52 }
    54 static void
    55 AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const gfx3DMatrix& aTransform)
    56 {
    57   nsIntRegionRectIterator iter(aSource);
    58   const nsIntRect *r;
    59   while ((r = iter.Next())) {
    60     aDest.Or(aDest, TransformRect(*r, aTransform));
    61   }
    62   aDest.SimplifyOutward(20);
    63 }
    65 static void
    66 AddRegion(nsIntRegion& aDest, const nsIntRegion& aSource)
    67 {
    68   aDest.Or(aDest, aSource);
    69   aDest.SimplifyOutward(20);
    70 }
    72 static nsIntRegion
    73 TransformRegion(const nsIntRegion& aRegion, const gfx3DMatrix& aTransform)
    74 {
    75   nsIntRegion result;
    76   AddTransformedRegion(result, aRegion, aTransform);
    77   return result;
    78 }
    80 /**
    81  * Walks over this layer, and all descendant layers.
    82  * If any of these are a ContainerLayer that reports invalidations to a PresShell,
    83  * then report that the entire bounds have changed.
    84  */
    85 static void
    86 NotifySubdocumentInvalidationRecursive(Layer* aLayer, NotifySubDocInvalidationFunc aCallback)
    87 {
    88   aLayer->ClearInvalidRect();
    89   ContainerLayer* container = aLayer->AsContainerLayer();
    91   if (aLayer->GetMaskLayer()) {
    92     NotifySubdocumentInvalidationRecursive(aLayer->GetMaskLayer(), aCallback);
    93   }
    95   if (!container) {
    96     return;
    97   }
    99   for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
   100     NotifySubdocumentInvalidationRecursive(child, aCallback);
   101   }
   103   aCallback(container, container->GetVisibleRegion());
   104 }
   106 struct LayerPropertiesBase : public LayerProperties
   107 {
   108   LayerPropertiesBase(Layer* aLayer)
   109     : mLayer(aLayer)
   110     , mMaskLayer(nullptr)
   111     , mVisibleRegion(aLayer->GetVisibleRegion())
   112     , mInvalidRegion(aLayer->GetInvalidRegion())
   113     , mOpacity(aLayer->GetLocalOpacity())
   114     , mUseClipRect(!!aLayer->GetClipRect())
   115   {
   116     MOZ_COUNT_CTOR(LayerPropertiesBase);
   117     if (aLayer->GetMaskLayer()) {
   118       mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer());
   119     }
   120     if (mUseClipRect) {
   121       mClipRect = *aLayer->GetClipRect();
   122     }
   123     gfx::To3DMatrix(aLayer->GetTransform(), mTransform);
   124   }
   125   LayerPropertiesBase()
   126     : mLayer(nullptr)
   127     , mMaskLayer(nullptr)
   128   {
   129     MOZ_COUNT_CTOR(LayerPropertiesBase);
   130   }
   131   ~LayerPropertiesBase()
   132   {
   133     MOZ_COUNT_DTOR(LayerPropertiesBase);
   134   }
   136   virtual nsIntRegion ComputeDifferences(Layer* aRoot, 
   137                                          NotifySubDocInvalidationFunc aCallback,
   138                                          bool* aGeometryChanged);
   140   virtual void MoveBy(const nsIntPoint& aOffset);
   142   nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback,
   143                             bool& aGeometryChanged)
   144   {
   145     gfx3DMatrix transform;
   146     gfx::To3DMatrix(mLayer->GetTransform(), transform);
   147     bool transformChanged = !mTransform.FuzzyEqual(transform);
   148     Layer* otherMask = mLayer->GetMaskLayer();
   149     const nsIntRect* otherClip = mLayer->GetClipRect();
   150     nsIntRegion result;
   151     if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
   152         (mUseClipRect != !!otherClip) ||
   153         mLayer->GetLocalOpacity() != mOpacity ||
   154         transformChanged) 
   155     {
   156       aGeometryChanged = true;
   157       result = OldTransformedBounds();
   158       if (transformChanged) {
   159         AddRegion(result, NewTransformedBounds());
   160       }
   162       // If we don't have to generate invalidations separately for child
   163       // layers then we can just stop here since we've already invalidated the entire
   164       // old and new bounds.
   165       if (!aCallback) {
   166         ClearInvalidations(mLayer);
   167         return result;
   168       }
   169     }
   171     nsIntRegion visible;
   172     visible.Xor(mVisibleRegion, mLayer->GetVisibleRegion());
   173     if (!visible.IsEmpty()) {
   174       aGeometryChanged = true;
   175     }
   176     AddTransformedRegion(result, visible, mTransform);
   178     AddRegion(result, ComputeChangeInternal(aCallback, aGeometryChanged));
   179     AddTransformedRegion(result, mLayer->GetInvalidRegion(), mTransform);
   181     if (mMaskLayer && otherMask) {
   182       AddTransformedRegion(result, mMaskLayer->ComputeChange(aCallback, aGeometryChanged),
   183                            mTransform);
   184     }
   186     if (mUseClipRect && otherClip) {
   187       if (!mClipRect.IsEqualInterior(*otherClip)) {
   188         nsIntRegion tmp; 
   189         tmp.Xor(mClipRect, *otherClip); 
   190         AddRegion(result, tmp);
   191       }
   192     }
   194     mLayer->ClearInvalidRect();
   195     return result;
   196   }
   198   nsIntRect NewTransformedBounds()
   199   {
   200     gfx3DMatrix transform;
   201     gfx::To3DMatrix(mLayer->GetTransform(), transform);
   202     return TransformRect(mLayer->GetVisibleRegion().GetBounds(), transform);
   203   }
   205   nsIntRect OldTransformedBounds()
   206   {
   207     return TransformRect(mVisibleRegion.GetBounds(), mTransform);
   208   }
   210   virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
   211                                             bool& aGeometryChanged)
   212   {
   213     return nsIntRect();
   214   }
   216   nsRefPtr<Layer> mLayer;
   217   nsAutoPtr<LayerPropertiesBase> mMaskLayer;
   218   nsIntRegion mVisibleRegion;
   219   nsIntRegion mInvalidRegion;
   220   gfx3DMatrix mTransform;
   221   float mOpacity;
   222   nsIntRect mClipRect;
   223   bool mUseClipRect;
   224 };
   226 struct ContainerLayerProperties : public LayerPropertiesBase
   227 {
   228   ContainerLayerProperties(ContainerLayer* aLayer)
   229     : LayerPropertiesBase(aLayer)
   230   {
   231     for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
   232       mChildren.AppendElement(CloneLayerTreePropertiesInternal(child));
   233     }
   234   }
   236   virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
   237                                             bool& aGeometryChanged)
   238   {
   239     ContainerLayer* container = mLayer->AsContainerLayer();
   240     nsIntRegion result;
   242     // A low frame rate is especially visible to users when scrolling, so we
   243     // particularly want to avoid unnecessary invalidation at that time. For us
   244     // here, that means avoiding unnecessary invalidation of child items when
   245     // other children are added to or removed from our container layer, since
   246     // that may be caused by children being scrolled in or out of view. We are
   247     // less concerned with children changing order.
   248     // TODO: Consider how we could avoid unnecessary invalidation when children
   249     // change order, and whether the overhead would be worth it.
   251     nsDataHashtable<nsPtrHashKey<Layer>, uint32_t> oldIndexMap(mChildren.Length());
   252     for (uint32_t i = 0; i < mChildren.Length(); ++i) {
   253       oldIndexMap.Put(mChildren[i]->mLayer, i);
   254     }
   256     uint32_t i = 0; // cursor into the old child list mChildren
   257     for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
   258       bool invalidateChildsCurrentArea = false;
   259       if (i < mChildren.Length()) {
   260         uint32_t childsOldIndex;
   261         if (oldIndexMap.Get(child, &childsOldIndex)) {
   262           if (childsOldIndex >= i) {
   263             // Invalidate the old areas of layers that used to be between the
   264             // current |child| and the previous |child| that was also in the
   265             // old list mChildren (if any of those children have been reordered
   266             // rather than removed, we will invalidate their new area when we
   267             // encounter them in the new list):
   268             for (uint32_t j = i; j < childsOldIndex; ++j) {
   269               AddRegion(result, mChildren[j]->OldTransformedBounds());
   270             }
   271             // Invalidate any regions of the child that have changed: 
   272             AddRegion(result, mChildren[childsOldIndex]->ComputeChange(aCallback, aGeometryChanged));
   273             i = childsOldIndex + 1;
   274           } else {
   275             // We've already seen this child in mChildren (which means it must
   276             // have been reordered) and invalidated its old area. We need to 
   277             // invalidate its new area too:
   278             invalidateChildsCurrentArea = true;
   279           }
   280         } else {
   281           // |child| is new
   282           invalidateChildsCurrentArea = true;
   283         }
   284       } else {
   285         // |child| is new, or was reordered to a higher index
   286         invalidateChildsCurrentArea = true;
   287       }
   288       if (invalidateChildsCurrentArea) {
   289         gfx3DMatrix transform;
   290         gfx::To3DMatrix(child->GetTransform(), transform);
   291         AddTransformedRegion(result, child->GetVisibleRegion(), transform);
   292         if (aCallback) {
   293           NotifySubdocumentInvalidationRecursive(child, aCallback);
   294         } else {
   295           ClearInvalidations(child);
   296         }
   297       }
   298     }
   300     // Process remaining removed children.
   301     while (i < mChildren.Length()) {
   302       AddRegion(result, mChildren[i]->OldTransformedBounds());
   303       i++;
   304     }
   306     if (aCallback) {
   307       aCallback(container, result);
   308     }
   310     gfx3DMatrix transform;
   311     gfx::To3DMatrix(mLayer->GetTransform(), transform);
   312     return TransformRegion(result, transform);
   313   }
   315   // The old list of children:
   316   nsAutoTArray<nsAutoPtr<LayerPropertiesBase>,1> mChildren;
   317 };
   319 struct ColorLayerProperties : public LayerPropertiesBase
   320 {
   321   ColorLayerProperties(ColorLayer *aLayer)
   322     : LayerPropertiesBase(aLayer)
   323     , mColor(aLayer->GetColor())
   324   { }
   326   virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
   327                                             bool& aGeometryChanged)
   328   {
   329     ColorLayer* color = static_cast<ColorLayer*>(mLayer.get());
   331     if (mColor != color->GetColor()) {
   332       return NewTransformedBounds();
   333     }
   335     return nsIntRegion();
   336   }
   338   gfxRGBA mColor;
   339 };
   341 struct ImageLayerProperties : public LayerPropertiesBase
   342 {
   343   ImageLayerProperties(ImageLayer* aImage)
   344     : LayerPropertiesBase(aImage)
   345     , mContainer(aImage->GetContainer())
   346     , mFilter(aImage->GetFilter())
   347     , mScaleToSize(aImage->GetScaleToSize())
   348     , mScaleMode(aImage->GetScaleMode())
   349   {
   350   }
   352   virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
   353                                             bool& aGeometryChanged)
   354   {
   355     ImageLayer* imageLayer = static_cast<ImageLayer*>(mLayer.get());
   357     if (!imageLayer->GetVisibleRegion().IsEqual(mVisibleRegion)) {
   358       nsIntRect result = NewTransformedBounds();
   359       result = result.Union(OldTransformedBounds());
   360       return result;
   361     }
   363     if (mContainer != imageLayer->GetContainer() ||
   364         mFilter != imageLayer->GetFilter() ||
   365         mScaleToSize != imageLayer->GetScaleToSize() ||
   366         mScaleMode != imageLayer->GetScaleMode()) {
   367       return NewTransformedBounds();
   368     }
   370     return nsIntRect();
   371   }
   373   nsRefPtr<ImageContainer> mContainer;
   374   GraphicsFilter mFilter;
   375   gfx::IntSize mScaleToSize;
   376   ScaleMode mScaleMode;
   377 };
   379 LayerPropertiesBase*
   380 CloneLayerTreePropertiesInternal(Layer* aRoot)
   381 {
   382   if (!aRoot) {
   383     return new LayerPropertiesBase();
   384   }
   386   switch (aRoot->GetType()) {
   387     case Layer::TYPE_CONTAINER:
   388     case Layer::TYPE_REF:
   389       return new ContainerLayerProperties(aRoot->AsContainerLayer());
   390     case Layer::TYPE_COLOR:
   391       return new ColorLayerProperties(static_cast<ColorLayer*>(aRoot));
   392     case Layer::TYPE_IMAGE:
   393       return new ImageLayerProperties(static_cast<ImageLayer*>(aRoot));
   394     default:
   395       return new LayerPropertiesBase(aRoot);
   396   }
   398   return nullptr;
   399 }
   401 /* static */ LayerProperties*
   402 LayerProperties::CloneFrom(Layer* aRoot)
   403 {
   404   return CloneLayerTreePropertiesInternal(aRoot);
   405 }
   407 /* static */ void 
   408 LayerProperties::ClearInvalidations(Layer *aLayer)
   409 {
   410   aLayer->ClearInvalidRect();
   411   if (aLayer->GetMaskLayer()) {
   412     ClearInvalidations(aLayer->GetMaskLayer());
   413   }
   415   ContainerLayer* container = aLayer->AsContainerLayer();
   416   if (!container) {
   417     return;
   418   }
   420   for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
   421     ClearInvalidations(child);
   422   }
   423 }
   425 nsIntRegion
   426 LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback,
   427                                         bool* aGeometryChanged = nullptr)
   428 {
   429   NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
   430   if (mLayer != aRoot) {
   431     if (aCallback) {
   432       NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
   433     } else {
   434       ClearInvalidations(aRoot);
   435     }
   436     gfx3DMatrix transform;
   437     gfx::To3DMatrix(aRoot->GetTransform(), transform);
   438     nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), transform);
   439     result = result.Union(OldTransformedBounds());
   440     if (aGeometryChanged != nullptr) {
   441       *aGeometryChanged = true;
   442     }
   443     return result;
   444   } else {
   445     bool geometryChanged = (aGeometryChanged != nullptr) ? *aGeometryChanged : false;
   446     nsIntRegion invalid = ComputeChange(aCallback, geometryChanged);
   447     if (aGeometryChanged != nullptr) {
   448       *aGeometryChanged = geometryChanged;
   449     }
   450     return invalid;
   451   }
   452 }
   454 void 
   455 LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset)
   456 {
   457   mTransform.TranslatePost(gfxPoint3D(aOffset.x, aOffset.y, 0)); 
   458 }
   460 } // namespace layers
   461 } // namespace mozilla

mercurial