1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/LayerTreeInvalidation.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,461 @@ 1.4 +/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "LayerTreeInvalidation.h" 1.10 +#include <stdint.h> // for uint32_t 1.11 +#include "ImageContainer.h" // for ImageContainer 1.12 +#include "ImageLayers.h" // for ImageLayer, etc 1.13 +#include "Layers.h" // for Layer, ContainerLayer, etc 1.14 +#include "gfx3DMatrix.h" // for gfx3DMatrix 1.15 +#include "gfxColor.h" // for gfxRGBA 1.16 +#include "GraphicsFilter.h" // for GraphicsFilter 1.17 +#include "gfxPoint3D.h" // for gfxPoint3D 1.18 +#include "gfxRect.h" // for gfxRect 1.19 +#include "gfxUtils.h" // for gfxUtils 1.20 +#include "mozilla/gfx/BaseSize.h" // for BaseSize 1.21 +#include "mozilla/gfx/Point.h" // for IntSize 1.22 +#include "mozilla/mozalloc.h" // for operator new, etc 1.23 +#include "nsAutoPtr.h" // for nsRefPtr, nsAutoPtr, etc 1.24 +#include "nsDataHashtable.h" // for nsDataHashtable 1.25 +#include "nsDebug.h" // for NS_ASSERTION 1.26 +#include "nsHashKeys.h" // for nsPtrHashKey 1.27 +#include "nsISupportsImpl.h" // for Layer::AddRef, etc 1.28 +#include "nsPoint.h" // for nsIntPoint 1.29 +#include "nsRect.h" // for nsIntRect 1.30 +#include "nsTArray.h" // for nsAutoTArray, nsTArray_Impl 1.31 + 1.32 +namespace mozilla { 1.33 +namespace layers { 1.34 + 1.35 +struct LayerPropertiesBase; 1.36 +LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot); 1.37 + 1.38 +static nsIntRect 1.39 +TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform) 1.40 +{ 1.41 + if (aRect.IsEmpty()) { 1.42 + return nsIntRect(); 1.43 + } 1.44 + 1.45 + gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height); 1.46 + rect = aTransform.TransformBounds(rect); 1.47 + rect.RoundOut(); 1.48 + 1.49 + nsIntRect intRect; 1.50 + if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) { 1.51 + return nsIntRect(); 1.52 + } 1.53 + 1.54 + return intRect; 1.55 +} 1.56 + 1.57 +static void 1.58 +AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const gfx3DMatrix& aTransform) 1.59 +{ 1.60 + nsIntRegionRectIterator iter(aSource); 1.61 + const nsIntRect *r; 1.62 + while ((r = iter.Next())) { 1.63 + aDest.Or(aDest, TransformRect(*r, aTransform)); 1.64 + } 1.65 + aDest.SimplifyOutward(20); 1.66 +} 1.67 + 1.68 +static void 1.69 +AddRegion(nsIntRegion& aDest, const nsIntRegion& aSource) 1.70 +{ 1.71 + aDest.Or(aDest, aSource); 1.72 + aDest.SimplifyOutward(20); 1.73 +} 1.74 + 1.75 +static nsIntRegion 1.76 +TransformRegion(const nsIntRegion& aRegion, const gfx3DMatrix& aTransform) 1.77 +{ 1.78 + nsIntRegion result; 1.79 + AddTransformedRegion(result, aRegion, aTransform); 1.80 + return result; 1.81 +} 1.82 + 1.83 +/** 1.84 + * Walks over this layer, and all descendant layers. 1.85 + * If any of these are a ContainerLayer that reports invalidations to a PresShell, 1.86 + * then report that the entire bounds have changed. 1.87 + */ 1.88 +static void 1.89 +NotifySubdocumentInvalidationRecursive(Layer* aLayer, NotifySubDocInvalidationFunc aCallback) 1.90 +{ 1.91 + aLayer->ClearInvalidRect(); 1.92 + ContainerLayer* container = aLayer->AsContainerLayer(); 1.93 + 1.94 + if (aLayer->GetMaskLayer()) { 1.95 + NotifySubdocumentInvalidationRecursive(aLayer->GetMaskLayer(), aCallback); 1.96 + } 1.97 + 1.98 + if (!container) { 1.99 + return; 1.100 + } 1.101 + 1.102 + for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { 1.103 + NotifySubdocumentInvalidationRecursive(child, aCallback); 1.104 + } 1.105 + 1.106 + aCallback(container, container->GetVisibleRegion()); 1.107 +} 1.108 + 1.109 +struct LayerPropertiesBase : public LayerProperties 1.110 +{ 1.111 + LayerPropertiesBase(Layer* aLayer) 1.112 + : mLayer(aLayer) 1.113 + , mMaskLayer(nullptr) 1.114 + , mVisibleRegion(aLayer->GetVisibleRegion()) 1.115 + , mInvalidRegion(aLayer->GetInvalidRegion()) 1.116 + , mOpacity(aLayer->GetLocalOpacity()) 1.117 + , mUseClipRect(!!aLayer->GetClipRect()) 1.118 + { 1.119 + MOZ_COUNT_CTOR(LayerPropertiesBase); 1.120 + if (aLayer->GetMaskLayer()) { 1.121 + mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer()); 1.122 + } 1.123 + if (mUseClipRect) { 1.124 + mClipRect = *aLayer->GetClipRect(); 1.125 + } 1.126 + gfx::To3DMatrix(aLayer->GetTransform(), mTransform); 1.127 + } 1.128 + LayerPropertiesBase() 1.129 + : mLayer(nullptr) 1.130 + , mMaskLayer(nullptr) 1.131 + { 1.132 + MOZ_COUNT_CTOR(LayerPropertiesBase); 1.133 + } 1.134 + ~LayerPropertiesBase() 1.135 + { 1.136 + MOZ_COUNT_DTOR(LayerPropertiesBase); 1.137 + } 1.138 + 1.139 + virtual nsIntRegion ComputeDifferences(Layer* aRoot, 1.140 + NotifySubDocInvalidationFunc aCallback, 1.141 + bool* aGeometryChanged); 1.142 + 1.143 + virtual void MoveBy(const nsIntPoint& aOffset); 1.144 + 1.145 + nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback, 1.146 + bool& aGeometryChanged) 1.147 + { 1.148 + gfx3DMatrix transform; 1.149 + gfx::To3DMatrix(mLayer->GetTransform(), transform); 1.150 + bool transformChanged = !mTransform.FuzzyEqual(transform); 1.151 + Layer* otherMask = mLayer->GetMaskLayer(); 1.152 + const nsIntRect* otherClip = mLayer->GetClipRect(); 1.153 + nsIntRegion result; 1.154 + if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask || 1.155 + (mUseClipRect != !!otherClip) || 1.156 + mLayer->GetLocalOpacity() != mOpacity || 1.157 + transformChanged) 1.158 + { 1.159 + aGeometryChanged = true; 1.160 + result = OldTransformedBounds(); 1.161 + if (transformChanged) { 1.162 + AddRegion(result, NewTransformedBounds()); 1.163 + } 1.164 + 1.165 + // If we don't have to generate invalidations separately for child 1.166 + // layers then we can just stop here since we've already invalidated the entire 1.167 + // old and new bounds. 1.168 + if (!aCallback) { 1.169 + ClearInvalidations(mLayer); 1.170 + return result; 1.171 + } 1.172 + } 1.173 + 1.174 + nsIntRegion visible; 1.175 + visible.Xor(mVisibleRegion, mLayer->GetVisibleRegion()); 1.176 + if (!visible.IsEmpty()) { 1.177 + aGeometryChanged = true; 1.178 + } 1.179 + AddTransformedRegion(result, visible, mTransform); 1.180 + 1.181 + AddRegion(result, ComputeChangeInternal(aCallback, aGeometryChanged)); 1.182 + AddTransformedRegion(result, mLayer->GetInvalidRegion(), mTransform); 1.183 + 1.184 + if (mMaskLayer && otherMask) { 1.185 + AddTransformedRegion(result, mMaskLayer->ComputeChange(aCallback, aGeometryChanged), 1.186 + mTransform); 1.187 + } 1.188 + 1.189 + if (mUseClipRect && otherClip) { 1.190 + if (!mClipRect.IsEqualInterior(*otherClip)) { 1.191 + nsIntRegion tmp; 1.192 + tmp.Xor(mClipRect, *otherClip); 1.193 + AddRegion(result, tmp); 1.194 + } 1.195 + } 1.196 + 1.197 + mLayer->ClearInvalidRect(); 1.198 + return result; 1.199 + } 1.200 + 1.201 + nsIntRect NewTransformedBounds() 1.202 + { 1.203 + gfx3DMatrix transform; 1.204 + gfx::To3DMatrix(mLayer->GetTransform(), transform); 1.205 + return TransformRect(mLayer->GetVisibleRegion().GetBounds(), transform); 1.206 + } 1.207 + 1.208 + nsIntRect OldTransformedBounds() 1.209 + { 1.210 + return TransformRect(mVisibleRegion.GetBounds(), mTransform); 1.211 + } 1.212 + 1.213 + virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, 1.214 + bool& aGeometryChanged) 1.215 + { 1.216 + return nsIntRect(); 1.217 + } 1.218 + 1.219 + nsRefPtr<Layer> mLayer; 1.220 + nsAutoPtr<LayerPropertiesBase> mMaskLayer; 1.221 + nsIntRegion mVisibleRegion; 1.222 + nsIntRegion mInvalidRegion; 1.223 + gfx3DMatrix mTransform; 1.224 + float mOpacity; 1.225 + nsIntRect mClipRect; 1.226 + bool mUseClipRect; 1.227 +}; 1.228 + 1.229 +struct ContainerLayerProperties : public LayerPropertiesBase 1.230 +{ 1.231 + ContainerLayerProperties(ContainerLayer* aLayer) 1.232 + : LayerPropertiesBase(aLayer) 1.233 + { 1.234 + for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { 1.235 + mChildren.AppendElement(CloneLayerTreePropertiesInternal(child)); 1.236 + } 1.237 + } 1.238 + 1.239 + virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, 1.240 + bool& aGeometryChanged) 1.241 + { 1.242 + ContainerLayer* container = mLayer->AsContainerLayer(); 1.243 + nsIntRegion result; 1.244 + 1.245 + // A low frame rate is especially visible to users when scrolling, so we 1.246 + // particularly want to avoid unnecessary invalidation at that time. For us 1.247 + // here, that means avoiding unnecessary invalidation of child items when 1.248 + // other children are added to or removed from our container layer, since 1.249 + // that may be caused by children being scrolled in or out of view. We are 1.250 + // less concerned with children changing order. 1.251 + // TODO: Consider how we could avoid unnecessary invalidation when children 1.252 + // change order, and whether the overhead would be worth it. 1.253 + 1.254 + nsDataHashtable<nsPtrHashKey<Layer>, uint32_t> oldIndexMap(mChildren.Length()); 1.255 + for (uint32_t i = 0; i < mChildren.Length(); ++i) { 1.256 + oldIndexMap.Put(mChildren[i]->mLayer, i); 1.257 + } 1.258 + 1.259 + uint32_t i = 0; // cursor into the old child list mChildren 1.260 + for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { 1.261 + bool invalidateChildsCurrentArea = false; 1.262 + if (i < mChildren.Length()) { 1.263 + uint32_t childsOldIndex; 1.264 + if (oldIndexMap.Get(child, &childsOldIndex)) { 1.265 + if (childsOldIndex >= i) { 1.266 + // Invalidate the old areas of layers that used to be between the 1.267 + // current |child| and the previous |child| that was also in the 1.268 + // old list mChildren (if any of those children have been reordered 1.269 + // rather than removed, we will invalidate their new area when we 1.270 + // encounter them in the new list): 1.271 + for (uint32_t j = i; j < childsOldIndex; ++j) { 1.272 + AddRegion(result, mChildren[j]->OldTransformedBounds()); 1.273 + } 1.274 + // Invalidate any regions of the child that have changed: 1.275 + AddRegion(result, mChildren[childsOldIndex]->ComputeChange(aCallback, aGeometryChanged)); 1.276 + i = childsOldIndex + 1; 1.277 + } else { 1.278 + // We've already seen this child in mChildren (which means it must 1.279 + // have been reordered) and invalidated its old area. We need to 1.280 + // invalidate its new area too: 1.281 + invalidateChildsCurrentArea = true; 1.282 + } 1.283 + } else { 1.284 + // |child| is new 1.285 + invalidateChildsCurrentArea = true; 1.286 + } 1.287 + } else { 1.288 + // |child| is new, or was reordered to a higher index 1.289 + invalidateChildsCurrentArea = true; 1.290 + } 1.291 + if (invalidateChildsCurrentArea) { 1.292 + gfx3DMatrix transform; 1.293 + gfx::To3DMatrix(child->GetTransform(), transform); 1.294 + AddTransformedRegion(result, child->GetVisibleRegion(), transform); 1.295 + if (aCallback) { 1.296 + NotifySubdocumentInvalidationRecursive(child, aCallback); 1.297 + } else { 1.298 + ClearInvalidations(child); 1.299 + } 1.300 + } 1.301 + } 1.302 + 1.303 + // Process remaining removed children. 1.304 + while (i < mChildren.Length()) { 1.305 + AddRegion(result, mChildren[i]->OldTransformedBounds()); 1.306 + i++; 1.307 + } 1.308 + 1.309 + if (aCallback) { 1.310 + aCallback(container, result); 1.311 + } 1.312 + 1.313 + gfx3DMatrix transform; 1.314 + gfx::To3DMatrix(mLayer->GetTransform(), transform); 1.315 + return TransformRegion(result, transform); 1.316 + } 1.317 + 1.318 + // The old list of children: 1.319 + nsAutoTArray<nsAutoPtr<LayerPropertiesBase>,1> mChildren; 1.320 +}; 1.321 + 1.322 +struct ColorLayerProperties : public LayerPropertiesBase 1.323 +{ 1.324 + ColorLayerProperties(ColorLayer *aLayer) 1.325 + : LayerPropertiesBase(aLayer) 1.326 + , mColor(aLayer->GetColor()) 1.327 + { } 1.328 + 1.329 + virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, 1.330 + bool& aGeometryChanged) 1.331 + { 1.332 + ColorLayer* color = static_cast<ColorLayer*>(mLayer.get()); 1.333 + 1.334 + if (mColor != color->GetColor()) { 1.335 + return NewTransformedBounds(); 1.336 + } 1.337 + 1.338 + return nsIntRegion(); 1.339 + } 1.340 + 1.341 + gfxRGBA mColor; 1.342 +}; 1.343 + 1.344 +struct ImageLayerProperties : public LayerPropertiesBase 1.345 +{ 1.346 + ImageLayerProperties(ImageLayer* aImage) 1.347 + : LayerPropertiesBase(aImage) 1.348 + , mContainer(aImage->GetContainer()) 1.349 + , mFilter(aImage->GetFilter()) 1.350 + , mScaleToSize(aImage->GetScaleToSize()) 1.351 + , mScaleMode(aImage->GetScaleMode()) 1.352 + { 1.353 + } 1.354 + 1.355 + virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback, 1.356 + bool& aGeometryChanged) 1.357 + { 1.358 + ImageLayer* imageLayer = static_cast<ImageLayer*>(mLayer.get()); 1.359 + 1.360 + if (!imageLayer->GetVisibleRegion().IsEqual(mVisibleRegion)) { 1.361 + nsIntRect result = NewTransformedBounds(); 1.362 + result = result.Union(OldTransformedBounds()); 1.363 + return result; 1.364 + } 1.365 + 1.366 + if (mContainer != imageLayer->GetContainer() || 1.367 + mFilter != imageLayer->GetFilter() || 1.368 + mScaleToSize != imageLayer->GetScaleToSize() || 1.369 + mScaleMode != imageLayer->GetScaleMode()) { 1.370 + return NewTransformedBounds(); 1.371 + } 1.372 + 1.373 + return nsIntRect(); 1.374 + } 1.375 + 1.376 + nsRefPtr<ImageContainer> mContainer; 1.377 + GraphicsFilter mFilter; 1.378 + gfx::IntSize mScaleToSize; 1.379 + ScaleMode mScaleMode; 1.380 +}; 1.381 + 1.382 +LayerPropertiesBase* 1.383 +CloneLayerTreePropertiesInternal(Layer* aRoot) 1.384 +{ 1.385 + if (!aRoot) { 1.386 + return new LayerPropertiesBase(); 1.387 + } 1.388 + 1.389 + switch (aRoot->GetType()) { 1.390 + case Layer::TYPE_CONTAINER: 1.391 + case Layer::TYPE_REF: 1.392 + return new ContainerLayerProperties(aRoot->AsContainerLayer()); 1.393 + case Layer::TYPE_COLOR: 1.394 + return new ColorLayerProperties(static_cast<ColorLayer*>(aRoot)); 1.395 + case Layer::TYPE_IMAGE: 1.396 + return new ImageLayerProperties(static_cast<ImageLayer*>(aRoot)); 1.397 + default: 1.398 + return new LayerPropertiesBase(aRoot); 1.399 + } 1.400 + 1.401 + return nullptr; 1.402 +} 1.403 + 1.404 +/* static */ LayerProperties* 1.405 +LayerProperties::CloneFrom(Layer* aRoot) 1.406 +{ 1.407 + return CloneLayerTreePropertiesInternal(aRoot); 1.408 +} 1.409 + 1.410 +/* static */ void 1.411 +LayerProperties::ClearInvalidations(Layer *aLayer) 1.412 +{ 1.413 + aLayer->ClearInvalidRect(); 1.414 + if (aLayer->GetMaskLayer()) { 1.415 + ClearInvalidations(aLayer->GetMaskLayer()); 1.416 + } 1.417 + 1.418 + ContainerLayer* container = aLayer->AsContainerLayer(); 1.419 + if (!container) { 1.420 + return; 1.421 + } 1.422 + 1.423 + for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { 1.424 + ClearInvalidations(child); 1.425 + } 1.426 +} 1.427 + 1.428 +nsIntRegion 1.429 +LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback, 1.430 + bool* aGeometryChanged = nullptr) 1.431 +{ 1.432 + NS_ASSERTION(aRoot, "Must have a layer tree to compare against!"); 1.433 + if (mLayer != aRoot) { 1.434 + if (aCallback) { 1.435 + NotifySubdocumentInvalidationRecursive(aRoot, aCallback); 1.436 + } else { 1.437 + ClearInvalidations(aRoot); 1.438 + } 1.439 + gfx3DMatrix transform; 1.440 + gfx::To3DMatrix(aRoot->GetTransform(), transform); 1.441 + nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), transform); 1.442 + result = result.Union(OldTransformedBounds()); 1.443 + if (aGeometryChanged != nullptr) { 1.444 + *aGeometryChanged = true; 1.445 + } 1.446 + return result; 1.447 + } else { 1.448 + bool geometryChanged = (aGeometryChanged != nullptr) ? *aGeometryChanged : false; 1.449 + nsIntRegion invalid = ComputeChange(aCallback, geometryChanged); 1.450 + if (aGeometryChanged != nullptr) { 1.451 + *aGeometryChanged = geometryChanged; 1.452 + } 1.453 + return invalid; 1.454 + } 1.455 +} 1.456 + 1.457 +void 1.458 +LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset) 1.459 +{ 1.460 + mTransform.TranslatePost(gfxPoint3D(aOffset.x, aOffset.y, 0)); 1.461 +} 1.462 + 1.463 +} // namespace layers 1.464 +} // namespace mozilla