gfx/layers/LayerTreeInvalidation.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.

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

mercurial