virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, bool& aGeometryChanged) { ImageLayer* imageLayer = static_cast<ImageLayer*>(mLayer.get()); if (!imageLayer->GetVisibleRegion().IsEqual(mVisibleRegion)) { aGeometryChanged = true; IntRect result = NewTransformedBounds(); result = result.Union(OldTransformedBounds()); return result; } ImageContainer* container = imageLayer->GetContainer(); if (mContainer != container || mFilter != imageLayer->GetFilter() || mScaleToSize != imageLayer->GetScaleToSize() || mScaleMode != imageLayer->GetScaleMode()) { aGeometryChanged = true; if (mIsMask) { // Mask layers have an empty visible region, so we have to // use the image size instead. IntSize size = container->GetCurrentSize(); IntRect rect(0, 0, size.width, size.height); return TransformRect(rect, mLayer->GetLocalTransform()); } else { return NewTransformedBounds(); } } return IntRect(); }
virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) { ImageLayer* image = static_cast<ImageLayer*>(mLayer); if (!image->GetVisibleRegion().IsEqual(mVisibleRegion)) { nsIntRect result = NewTransformedBounds(); result = result.Union(OldTransformedBounds()); return result; } if (mContainer != image->GetContainer() || mFilter != image->GetFilter() || mScaleToSize != image->GetScaleToSize() || mScaleMode != image->GetScaleMode()) { return NewTransformedBounds(); } return nsIntRect(); }
virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) { ColorLayer* color = static_cast<ColorLayer*>(mLayer); if (mColor != color->GetColor()) { return NewTransformedBounds(); } return nsIntRect(); }
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; }
virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, bool& aGeometryChanged) { ColorLayer* color = static_cast<ColorLayer*>(mLayer.get()); if (mColor != color->GetColor()) { aGeometryChanged = true; return NewTransformedBounds(); } nsIntRegion boundsDiff; boundsDiff.Xor(mBounds, color->GetBounds()); nsIntRegion result; AddTransformedRegion(result, boundsDiff, mTransform); return result; }
nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback, bool& aGeometryChanged) { bool transformChanged = !mTransform.FuzzyEqual(mLayer->GetLocalTransform()) || mLayer->GetPostXScale() != mPostXScale || mLayer->GetPostYScale() != mPostYScale; Layer* otherMask = mLayer->GetMaskLayer(); const Maybe<ParentLayerIntRect>& otherClip = mLayer->GetClipRect(); nsIntRegion result; if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask || (mUseClipRect != !!otherClip) || mLayer->GetLocalOpacity() != mOpacity || transformChanged) { aGeometryChanged = true; result = OldTransformedBounds(); AddRegion(result, NewTransformedBounds()); // We can't bail out early because we need to update mChildrenChanged. } AddRegion(result, ComputeChangeInternal(aCallback, aGeometryChanged)); AddTransformedRegion(result, mLayer->GetInvalidRegion(), mTransform); if (mMaskLayer && otherMask) { AddTransformedRegion(result, mMaskLayer->ComputeChange(aCallback, aGeometryChanged), mTransform); } if (mUseClipRect && otherClip) { if (!mClipRect.IsEqualInterior(*otherClip)) { aGeometryChanged = true; nsIntRegion tmp; tmp.Xor(ParentLayerIntRect::ToUntyped(mClipRect), ParentLayerIntRect::ToUntyped(*otherClip)); AddRegion(result, tmp); } } mLayer->ClearInvalidRect(); return result; }
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; }