nsIntRegion
LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback,
                                        bool* aGeometryChanged = nullptr)
{
  NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
  if (mLayer != aRoot) {
    if (aCallback) {
      NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
    } else {
      ClearInvalidations(aRoot);
    }
    IntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(),
                                     aRoot->GetLocalTransform());
    result = result.Union(OldTransformedBounds());
    if (aGeometryChanged != nullptr) {
      *aGeometryChanged = true;
    }
    return result;
  } else {
    bool geometryChanged = (aGeometryChanged != nullptr) ? *aGeometryChanged : false;
    nsIntRegion invalid = ComputeChange(aCallback, geometryChanged);
    if (aGeometryChanged != nullptr) {
      *aGeometryChanged = geometryChanged;
    }
    return invalid;
  }
}
/* static */ void
LayerProperties::ClearInvalidations(Layer *aLayer)
{
    aLayer->ClearInvalidRect();
    if (aLayer->GetMaskLayer()) {
        ClearInvalidations(aLayer->GetMaskLayer());
    }

    ContainerLayer* container = aLayer->AsContainerLayer();
    if (!container) {
        return;
    }

    for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
        ClearInvalidations(child);
    }
}
  nsIntRect ComputeChange(NotifySubDocInvalidationFunc aCallback)
  {
    bool transformChanged = mTransform != mLayer->GetTransform();
    Layer* otherMask = mLayer->GetMaskLayer();
    const nsIntRect* otherClip = mLayer->GetClipRect();
    nsIntRect result;
    if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
        (mUseClipRect != !!otherClip) ||
        mLayer->GetOpacity() != mOpacity ||
        transformChanged) 
    {
      result = OldTransformedBounds();
      if (transformChanged) {
        result = result.Union(NewTransformedBounds());
      }

      // If we don't have to generate invalidations separately for child
      // layers then we can just stop here since we've already invalidated the entire
      // old and new bounds.
      if (!aCallback) {
        ClearInvalidations(mLayer);
        return result;
      }
    }

    nsIntRegion visible;
    visible.Xor(mVisibleRegion, mLayer->GetVisibleRegion());
    result = result.Union(TransformRect(visible.GetBounds(), mTransform));

    result = result.Union(ComputeChangeInternal(aCallback));
    result = result.Union(TransformRect(mLayer->GetInvalidRegion().GetBounds(), mTransform));

    if (mMaskLayer && otherMask) {
      nsIntRect maskDiff = mMaskLayer->ComputeChange(aCallback);
      result = result.Union(TransformRect(maskDiff, mTransform));
    }

    if (mUseClipRect && otherClip) {
      if (!mClipRect.IsEqualInterior(*otherClip)) {
        nsIntRegion tmp; 
        tmp.Xor(mClipRect, *otherClip); 
        result = result.Union(tmp.GetBounds());
      }
    }

    mLayer->ClearInvalidRect();
    return result;
  }
nsIntRect
LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback)
{
    NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
    if (mLayer != aRoot) {
        if (aCallback) {
            NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
        } else {
            ClearInvalidations(aRoot);
        }
        nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), aRoot->GetTransform());
        result = result.Union(OldTransformedBounds());
        return result;
    } else {
        return ComputeChange(aCallback);
    }
}
    virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback)
    {
        ContainerLayer* container = mLayer->AsContainerLayer();
        nsIntRegion result;

        PRUint32 i = 0;
        for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
            if (i >= mChildren.Length() || child != mChildren[i]->mLayer) {
                // Child change. Invalidate the full areas.
                // TODO: We could be smarter here if non-overlapping children
                // swap order.
                result.Or(result, TransformRect(child->GetVisibleRegion().GetBounds(), child->GetTransform()));
                if (i < mChildren.Length()) {
                    result.Or(result, mChildren[i]->OldTransformedBounds());
                }
                if (aCallback) {
                    NotifySubdocumentInvalidationRecursive(child, aCallback);
                } else {
                    ClearInvalidations(child);
                }
            } else {
                // Same child, check for differences within the child
                result.Or(result, mChildren[i]->ComputeChange(aCallback));
            }

            i++;
        }

        // Process remaining removed children.
        while (i < mChildren.Length()) {
            result.Or(result, mChildren[i]->OldTransformedBounds());
            i++;
        }

        if (aCallback) {
            aCallback(container, result);
        }

        return TransformRect(result.GetBounds(), mLayer->GetTransform());
    }
  virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
                                            bool& aGeometryChanged)
  {
    ContainerLayer* container = mLayer->AsContainerLayer();
    nsIntRegion result;

    bool childrenChanged = false;

    if (mPreXScale != container->GetPreXScale() ||
        mPreYScale != container->GetPreYScale()) {
      aGeometryChanged = true;
      result = OldTransformedBounds();
      AddRegion(result, NewTransformedBounds());
      childrenChanged = true;

      // Can't bail out early, we need to update the child container layers
    }

    // A low frame rate is especially visible to users when scrolling, so we
    // particularly want to avoid unnecessary invalidation at that time. For us
    // here, that means avoiding unnecessary invalidation of child items when
    // other children are added to or removed from our container layer, since
    // that may be caused by children being scrolled in or out of view. We are
    // less concerned with children changing order.
    // TODO: Consider how we could avoid unnecessary invalidation when children
    // change order, and whether the overhead would be worth it.

    nsDataHashtable<nsPtrHashKey<Layer>, uint32_t> oldIndexMap(mChildren.Length());
    for (uint32_t i = 0; i < mChildren.Length(); ++i) {
      oldIndexMap.Put(mChildren[i]->mLayer, i);
    }

    uint32_t i = 0; // cursor into the old child list mChildren
    for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
      bool invalidateChildsCurrentArea = false;
      if (i < mChildren.Length()) {
        uint32_t childsOldIndex;
        if (oldIndexMap.Get(child, &childsOldIndex)) {
          if (childsOldIndex >= i) {
            // Invalidate the old areas of layers that used to be between the
            // current |child| and the previous |child| that was also in the
            // old list mChildren (if any of those children have been reordered
            // rather than removed, we will invalidate their new area when we
            // encounter them in the new list):
            for (uint32_t j = i; j < childsOldIndex; ++j) {
              AddRegion(result, mChildren[j]->OldTransformedBounds());
              childrenChanged |= true;
            }
            // Invalidate any regions of the child that have changed:
            nsIntRegion region = mChildren[childsOldIndex]->ComputeChange(aCallback, aGeometryChanged);
            i = childsOldIndex + 1;
            if (!region.IsEmpty()) {
              AddRegion(result, region);
              childrenChanged |= true;
            }
          } else {
            // We've already seen this child in mChildren (which means it must
            // have been reordered) and invalidated its old area. We need to
            // invalidate its new area too:
            invalidateChildsCurrentArea = true;
          }
        } else {
          // |child| is new
          invalidateChildsCurrentArea = true;
        }
      } else {
        // |child| is new, or was reordered to a higher index
        invalidateChildsCurrentArea = true;
      }
      if (invalidateChildsCurrentArea) {
        aGeometryChanged = true;
        AddTransformedRegion(result, child->GetVisibleRegion(), child->GetLocalTransform());
        if (aCallback) {
          NotifySubdocumentInvalidationRecursive(child, aCallback);
        } else {
          ClearInvalidations(child);
        }
      }
      childrenChanged |= invalidateChildsCurrentArea;
    }

    // Process remaining removed children.
    while (i < mChildren.Length()) {
      childrenChanged |= true;
      AddRegion(result, mChildren[i]->OldTransformedBounds());
      i++;
    }

    if (aCallback) {
      aCallback(container, result);
    }

    if (childrenChanged) {
      container->SetChildrenChanged(true);
    }

    result.Transform(gfx::To3DMatrix(mLayer->GetLocalTransform()));

    return result;
  }