1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/FrameLayerBuilder.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,4036 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; 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 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/DebugOnly.h" 1.10 + 1.11 +#include "FrameLayerBuilder.h" 1.12 + 1.13 +#include "nsDisplayList.h" 1.14 +#include "nsPresContext.h" 1.15 +#include "nsLayoutUtils.h" 1.16 +#include "Layers.h" 1.17 +#include "BasicLayers.h" 1.18 +#include "gfxUtils.h" 1.19 +#include "nsRenderingContext.h" 1.20 +#include "MaskLayerImageCache.h" 1.21 +#include "nsIScrollableFrame.h" 1.22 +#include "nsPrintfCString.h" 1.23 +#include "LayerTreeInvalidation.h" 1.24 +#include "nsSVGIntegrationUtils.h" 1.25 +#include "ImageContainer.h" 1.26 +#include "ActiveLayerTracker.h" 1.27 +#include "gfx2DGlue.h" 1.28 + 1.29 +#include "GeckoProfiler.h" 1.30 +#include "mozilla/gfx/Tools.h" 1.31 +#include "mozilla/gfx/2D.h" 1.32 +#include "gfxPrefs.h" 1.33 + 1.34 +#include <algorithm> 1.35 + 1.36 +using namespace mozilla::layers; 1.37 +using namespace mozilla::gfx; 1.38 + 1.39 +namespace mozilla { 1.40 + 1.41 +class ContainerState; 1.42 + 1.43 +FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey, 1.44 + Layer* aLayer, LayerState aLayerState, uint32_t aGeneration) 1.45 + 1.46 + : mParent(aParent) 1.47 + , mLayer(aLayer) 1.48 + , mDisplayItemKey(aKey) 1.49 + , mContainerLayerGeneration(aGeneration) 1.50 + , mLayerState(aLayerState) 1.51 + , mUsed(true) 1.52 + , mIsInvalid(false) 1.53 +{ 1.54 +} 1.55 + 1.56 +FrameLayerBuilder::DisplayItemData::DisplayItemData(DisplayItemData &toCopy) 1.57 +{ 1.58 + // This isn't actually a copy-constructor; notice that it steals toCopy's 1.59 + // mGeometry pointer. Be careful. 1.60 + mParent = toCopy.mParent; 1.61 + mLayer = toCopy.mLayer; 1.62 + mInactiveManager = toCopy.mInactiveManager; 1.63 + mFrameList = toCopy.mFrameList; 1.64 + mGeometry = toCopy.mGeometry; 1.65 + mDisplayItemKey = toCopy.mDisplayItemKey; 1.66 + mClip = toCopy.mClip; 1.67 + mContainerLayerGeneration = toCopy.mContainerLayerGeneration; 1.68 + mLayerState = toCopy.mLayerState; 1.69 + mUsed = toCopy.mUsed; 1.70 +} 1.71 + 1.72 +void 1.73 +FrameLayerBuilder::DisplayItemData::AddFrame(nsIFrame* aFrame) 1.74 +{ 1.75 + mFrameList.AppendElement(aFrame); 1.76 + 1.77 + nsTArray<DisplayItemData*> *array = 1.78 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty())); 1.79 + if (!array) { 1.80 + array = new nsTArray<DisplayItemData*>(); 1.81 + aFrame->Properties().Set(FrameLayerBuilder::LayerManagerDataProperty(), array); 1.82 + } 1.83 + array->AppendElement(this); 1.84 +} 1.85 + 1.86 +void 1.87 +FrameLayerBuilder::DisplayItemData::RemoveFrame(nsIFrame* aFrame) 1.88 +{ 1.89 + DebugOnly<bool> result = mFrameList.RemoveElement(aFrame); 1.90 + NS_ASSERTION(result, "Can't remove a frame that wasn't added!"); 1.91 + 1.92 + nsTArray<DisplayItemData*> *array = 1.93 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty())); 1.94 + NS_ASSERTION(array, "Must be already stored on the frame!"); 1.95 + array->RemoveElement(this); 1.96 +} 1.97 + 1.98 +void 1.99 +FrameLayerBuilder::DisplayItemData::UpdateContents(Layer* aLayer, LayerState aState, 1.100 + uint32_t aContainerLayerGeneration, 1.101 + nsDisplayItem* aItem /* = nullptr */) 1.102 +{ 1.103 + mLayer = aLayer; 1.104 + mOptLayer = nullptr; 1.105 + mInactiveManager = nullptr; 1.106 + mLayerState = aState; 1.107 + mContainerLayerGeneration = aContainerLayerGeneration; 1.108 + mGeometry = nullptr; 1.109 + mClip = DisplayItemClip(); 1.110 + mUsed = true; 1.111 + 1.112 + if (!aItem) { 1.113 + return; 1.114 + } 1.115 + 1.116 + nsAutoTArray<nsIFrame*, 4> copy(mFrameList); 1.117 + if (!copy.RemoveElement(aItem->Frame())) { 1.118 + AddFrame(aItem->Frame()); 1.119 + } 1.120 + 1.121 + nsAutoTArray<nsIFrame*,4> mergedFrames; 1.122 + aItem->GetMergedFrames(&mergedFrames); 1.123 + for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { 1.124 + if (!copy.RemoveElement(mergedFrames[i])) { 1.125 + AddFrame(mergedFrames[i]); 1.126 + } 1.127 + } 1.128 + 1.129 + for (uint32_t i = 0; i < copy.Length(); i++) { 1.130 + RemoveFrame(copy[i]); 1.131 + } 1.132 +} 1.133 + 1.134 +static nsIFrame* sDestroyedFrame = nullptr; 1.135 +FrameLayerBuilder::DisplayItemData::~DisplayItemData() 1.136 +{ 1.137 + for (uint32_t i = 0; i < mFrameList.Length(); i++) { 1.138 + nsIFrame* frame = mFrameList[i]; 1.139 + if (frame == sDestroyedFrame) { 1.140 + continue; 1.141 + } 1.142 + nsTArray<DisplayItemData*> *array = 1.143 + reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->Properties().Get(LayerManagerDataProperty())); 1.144 + array->RemoveElement(this); 1.145 + } 1.146 +} 1.147 + 1.148 +void 1.149 +FrameLayerBuilder::DisplayItemData::GetFrameListChanges(nsDisplayItem* aOther, 1.150 + nsTArray<nsIFrame*>& aOut) 1.151 +{ 1.152 + aOut = mFrameList; 1.153 + nsAutoTArray<nsIFrame*, 4> added; 1.154 + if (!aOut.RemoveElement(aOther->Frame())) { 1.155 + added.AppendElement(aOther->Frame()); 1.156 + } 1.157 + 1.158 + nsAutoTArray<nsIFrame*,4> mergedFrames; 1.159 + aOther->GetMergedFrames(&mergedFrames); 1.160 + for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { 1.161 + if (!aOut.RemoveElement(mergedFrames[i])) { 1.162 + added.AppendElement(mergedFrames[i]); 1.163 + } 1.164 + } 1.165 + 1.166 + aOut.AppendElements(added); 1.167 +} 1.168 + 1.169 +/** 1.170 + * This is the userdata we associate with a layer manager. 1.171 + */ 1.172 +class LayerManagerData : public LayerUserData { 1.173 +public: 1.174 + LayerManagerData(LayerManager *aManager) 1.175 + : mLayerManager(aManager) 1.176 +#ifdef DEBUG_DISPLAY_ITEM_DATA 1.177 + , mParent(nullptr) 1.178 +#endif 1.179 + , mInvalidateAllLayers(false) 1.180 + { 1.181 + MOZ_COUNT_CTOR(LayerManagerData); 1.182 + } 1.183 + ~LayerManagerData() { 1.184 + MOZ_COUNT_DTOR(LayerManagerData); 1.185 + } 1.186 + 1.187 +#ifdef DEBUG_DISPLAY_ITEM_DATA 1.188 + void Dump(const char *aPrefix = "") { 1.189 + printf_stderr("%sLayerManagerData %p\n", aPrefix, this); 1.190 + nsAutoCString prefix; 1.191 + prefix += aPrefix; 1.192 + prefix += " "; 1.193 + mDisplayItems.EnumerateEntries( 1.194 + FrameLayerBuilder::DumpDisplayItemDataForFrame, (void*)prefix.get()); 1.195 + } 1.196 +#endif 1.197 + 1.198 + /** 1.199 + * Tracks which frames have layers associated with them. 1.200 + */ 1.201 + LayerManager *mLayerManager; 1.202 +#ifdef DEBUG_DISPLAY_ITEM_DATA 1.203 + LayerManagerData *mParent; 1.204 +#endif 1.205 + nsTHashtable<nsRefPtrHashKey<FrameLayerBuilder::DisplayItemData> > mDisplayItems; 1.206 + bool mInvalidateAllLayers; 1.207 +}; 1.208 + 1.209 +/* static */ void 1.210 +FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame) 1.211 +{ 1.212 + FrameProperties props = aFrame->Properties(); 1.213 + props.Delete(LayerManagerDataProperty()); 1.214 +} 1.215 + 1.216 +// a global cache of image containers used for mask layers 1.217 +static MaskLayerImageCache* gMaskLayerImageCache = nullptr; 1.218 + 1.219 +static inline MaskLayerImageCache* GetMaskLayerImageCache() 1.220 +{ 1.221 + if (!gMaskLayerImageCache) { 1.222 + gMaskLayerImageCache = new MaskLayerImageCache(); 1.223 + } 1.224 + 1.225 + return gMaskLayerImageCache; 1.226 +} 1.227 + 1.228 +/** 1.229 + * We keep a stack of these to represent the ThebesLayers that are 1.230 + * currently available to have display items added to. 1.231 + * We use a stack here because as much as possible we want to 1.232 + * assign display items to existing ThebesLayers, and to the lowest 1.233 + * ThebesLayer in z-order. This reduces the number of layers and 1.234 + * makes it more likely a display item will be rendered to an opaque 1.235 + * layer, giving us the best chance of getting subpixel AA. 1.236 + */ 1.237 +class ThebesLayerData { 1.238 +public: 1.239 + ThebesLayerData() : 1.240 + mAnimatedGeometryRoot(nullptr), 1.241 + mFixedPosFrameForLayerData(nullptr), 1.242 + mReferenceFrame(nullptr), 1.243 + mLayer(nullptr), 1.244 + mIsSolidColorInVisibleRegion(false), 1.245 + mSingleItemFixedToViewport(false), 1.246 + mNeedComponentAlpha(false), 1.247 + mForceTransparentSurface(false), 1.248 + mImage(nullptr), 1.249 + mCommonClipCount(-1), 1.250 + mAllDrawingAbove(false) 1.251 + {} 1.252 + /** 1.253 + * Record that an item has been added to the ThebesLayer, so we 1.254 + * need to update our regions. 1.255 + * @param aVisibleRect the area of the item that's visible 1.256 + * @param aDrawRect the area of the item that would be drawn if it 1.257 + * was completely visible 1.258 + * @param aOpaqueRect if non-null, the area of the item that's opaque. 1.259 + * We pass in a separate opaque rect because the opaque rect can be 1.260 + * bigger than the visible rect, and we want to have the biggest 1.261 + * opaque rect that we can. 1.262 + * @param aSolidColor if non-null, the visible area of the item is 1.263 + * a constant color given by *aSolidColor 1.264 + */ 1.265 + void Accumulate(ContainerState* aState, 1.266 + nsDisplayItem* aItem, 1.267 + const nsIntRect& aVisibleRect, 1.268 + const nsIntRect& aDrawRect, 1.269 + const DisplayItemClip& aClip); 1.270 + const nsIFrame* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; } 1.271 + 1.272 + /** 1.273 + * Add aHitRegion and aDispatchToContentHitRegion to the hit regions for 1.274 + * this ThebesLayer. 1.275 + */ 1.276 + void AccumulateEventRegions(const nsIntRegion& aHitRegion, 1.277 + const nsIntRegion& aMaybeHitRegion, 1.278 + const nsIntRegion& aDispatchToContentHitRegion) 1.279 + { 1.280 + mHitRegion.Or(mHitRegion, aHitRegion); 1.281 + mMaybeHitRegion.Or(mMaybeHitRegion, aMaybeHitRegion); 1.282 + mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aDispatchToContentHitRegion); 1.283 + } 1.284 + 1.285 + /** 1.286 + * If this represents only a nsDisplayImage, and the image type 1.287 + * supports being optimized to an ImageLayer (TYPE_RASTER only) returns 1.288 + * an ImageContainer for the image. 1.289 + */ 1.290 + already_AddRefed<ImageContainer> CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder); 1.291 + 1.292 + void AddDrawAboveRegion(const nsIntRegion& aAbove) 1.293 + { 1.294 + if (!mAllDrawingAbove) { 1.295 + mDrawAboveRegion.Or(mDrawAboveRegion, aAbove); 1.296 + mDrawAboveRegion.SimplifyOutward(4); 1.297 + } 1.298 + } 1.299 + 1.300 + void AddVisibleAboveRegion(const nsIntRegion& aAbove) 1.301 + { 1.302 + if (!mAllDrawingAbove) { 1.303 + mVisibleAboveRegion.Or(mVisibleAboveRegion, aAbove); 1.304 + mVisibleAboveRegion.SimplifyOutward(4); 1.305 + } 1.306 + } 1.307 + 1.308 + void CopyAboveRegion(ThebesLayerData* aOther) 1.309 + { 1.310 + if (aOther->mAllDrawingAbove || mAllDrawingAbove) { 1.311 + SetAllDrawingAbove(); 1.312 + } else { 1.313 + mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleAboveRegion); 1.314 + mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleRegion); 1.315 + mVisibleAboveRegion.SimplifyOutward(4); 1.316 + mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawAboveRegion); 1.317 + mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawRegion); 1.318 + mDrawAboveRegion.SimplifyOutward(4); 1.319 + } 1.320 + } 1.321 + 1.322 + void SetAllDrawingAbove() 1.323 + { 1.324 + mAllDrawingAbove = true; 1.325 + mDrawAboveRegion.SetEmpty(); 1.326 + mVisibleAboveRegion.SetEmpty(); 1.327 + } 1.328 + 1.329 + bool DrawAboveRegionIntersects(const nsIntRect& aRect) 1.330 + { 1.331 + return mAllDrawingAbove || mDrawAboveRegion.Intersects(aRect); 1.332 + } 1.333 + 1.334 + bool DrawRegionIntersects(const nsIntRect& aRect) 1.335 + { 1.336 + return IsSubjectToAsyncTransforms() || mDrawRegion.Intersects(aRect); 1.337 + } 1.338 + 1.339 + bool IntersectsVisibleAboveRegion(const nsIntRegion& aVisibleRegion) 1.340 + { 1.341 + if (mAllDrawingAbove) { 1.342 + return true; 1.343 + } 1.344 + nsIntRegion visibleAboveIntersection; 1.345 + visibleAboveIntersection.And(mVisibleAboveRegion, aVisibleRegion); 1.346 + if (visibleAboveIntersection.IsEmpty()) { 1.347 + return false; 1.348 + } 1.349 + return true; 1.350 + } 1.351 + 1.352 + bool IsSubjectToAsyncTransforms() 1.353 + { 1.354 + return mFixedPosFrameForLayerData != nullptr; 1.355 + } 1.356 + 1.357 + /** 1.358 + * The region of visible content in the layer, relative to the 1.359 + * container layer (which is at the snapped top-left of the display 1.360 + * list reference frame). 1.361 + */ 1.362 + nsIntRegion mVisibleRegion; 1.363 + /** 1.364 + * The region containing the bounds of all display items in the layer, 1.365 + * regardless of visbility. 1.366 + * Same coordinate system as mVisibleRegion. 1.367 + * This is a conservative approximation: it contains the true region. 1.368 + */ 1.369 + nsIntRegion mDrawRegion; 1.370 + /** 1.371 + * The region of visible content in the layer that is opaque. 1.372 + * Same coordinate system as mVisibleRegion. 1.373 + */ 1.374 + nsIntRegion mOpaqueRegion; 1.375 + /** 1.376 + * The definitely-hit region for this ThebesLayer. 1.377 + */ 1.378 + nsIntRegion mHitRegion; 1.379 + /** 1.380 + * The maybe-hit region for this ThebesLayer. 1.381 + */ 1.382 + nsIntRegion mMaybeHitRegion; 1.383 + /** 1.384 + * The dispatch-to-content hit region for this ThebesLayer. 1.385 + */ 1.386 + nsIntRegion mDispatchToContentHitRegion; 1.387 + /** 1.388 + * The "active scrolled root" for all content in the layer. Must 1.389 + * be non-null; all content in a ThebesLayer must have the same 1.390 + * active scrolled root. 1.391 + */ 1.392 + const nsIFrame* mAnimatedGeometryRoot; 1.393 + /** 1.394 + * If non-null, the frame from which we'll extract "fixed positioning" 1.395 + * metadata for this layer. This can be a position:fixed frame or a viewport 1.396 + * frame; the latter case is used for background-attachment:fixed content. 1.397 + */ 1.398 + const nsIFrame* mFixedPosFrameForLayerData; 1.399 + const nsIFrame* mReferenceFrame; 1.400 + ThebesLayer* mLayer; 1.401 + /** 1.402 + * If mIsSolidColorInVisibleRegion is true, this is the color of the visible 1.403 + * region. 1.404 + */ 1.405 + nscolor mSolidColor; 1.406 + /** 1.407 + * True if every pixel in mVisibleRegion will have color mSolidColor. 1.408 + */ 1.409 + bool mIsSolidColorInVisibleRegion; 1.410 + /** 1.411 + * True if the layer contains exactly one item that returned true for 1.412 + * ShouldFixToViewport. 1.413 + */ 1.414 + bool mSingleItemFixedToViewport; 1.415 + /** 1.416 + * True if there is any text visible in the layer that's over 1.417 + * transparent pixels in the layer. 1.418 + */ 1.419 + bool mNeedComponentAlpha; 1.420 + /** 1.421 + * Set if the layer should be treated as transparent, even if its entire 1.422 + * area is covered by opaque display items. For example, this needs to 1.423 + * be set if something is going to "punch holes" in the layer by clearing 1.424 + * part of its surface. 1.425 + */ 1.426 + bool mForceTransparentSurface; 1.427 + 1.428 + /** 1.429 + * Stores the pointer to the nsDisplayImage if we want to 1.430 + * convert this to an ImageLayer. 1.431 + */ 1.432 + nsDisplayImageContainer* mImage; 1.433 + /** 1.434 + * Stores the clip that we need to apply to the image or, if there is no 1.435 + * image, a clip for SOME item in the layer. There is no guarantee which 1.436 + * item's clip will be stored here and mItemClip should not be used to clip 1.437 + * the whole layer - only some part of the clip should be used, as determined 1.438 + * by ThebesDisplayItemLayerUserData::GetCommonClipCount() - which may even be 1.439 + * no part at all. 1.440 + */ 1.441 + DisplayItemClip mItemClip; 1.442 + /** 1.443 + * The first mCommonClipCount rounded rectangle clips are identical for 1.444 + * all items in the layer. 1.445 + * -1 if there are no items in the layer; must be >=0 by the time that this 1.446 + * data is popped from the stack. 1.447 + */ 1.448 + int32_t mCommonClipCount; 1.449 + /* 1.450 + * Updates mCommonClipCount by checking for rounded rect clips in common 1.451 + * between the clip on a new item (aCurrentClip) and the common clips 1.452 + * on items already in the layer (the first mCommonClipCount rounded rects 1.453 + * in mItemClip). 1.454 + */ 1.455 + void UpdateCommonClipCount(const DisplayItemClip& aCurrentClip); 1.456 + 1.457 +private: 1.458 + /** 1.459 + * The region of visible content above the layer and below the 1.460 + * next ThebesLayerData currently in the stack, if any. Note that not 1.461 + * all ThebesLayers for the container are in the ThebesLayerData stack. 1.462 + * Same coordinate system as mVisibleRegion. 1.463 + * This is a conservative approximation: it contains the true region. 1.464 + */ 1.465 + nsIntRegion mVisibleAboveRegion; 1.466 + /** 1.467 + * The region containing the bounds of all display items (regardless 1.468 + * of visibility) in the layer and below the next ThebesLayerData 1.469 + * currently in the stack, if any. 1.470 + * Note that not all ThebesLayers for the container are in the 1.471 + * ThebesLayerData stack. 1.472 + * Same coordinate system as mVisibleRegion. 1.473 + */ 1.474 + nsIntRegion mDrawAboveRegion; 1.475 + /** 1.476 + * True if mDrawAboveRegion and mVisibleAboveRegion should be treated 1.477 + * as infinite, and all display items should be considered 'above' this layer. 1.478 + */ 1.479 + bool mAllDrawingAbove; 1.480 +}; 1.481 + 1.482 +/** 1.483 + * This is a helper object used to build up the layer children for 1.484 + * a ContainerLayer. 1.485 + */ 1.486 +class ContainerState { 1.487 +public: 1.488 + ContainerState(nsDisplayListBuilder* aBuilder, 1.489 + LayerManager* aManager, 1.490 + FrameLayerBuilder* aLayerBuilder, 1.491 + nsIFrame* aContainerFrame, 1.492 + nsDisplayItem* aContainerItem, 1.493 + ContainerLayer* aContainerLayer, 1.494 + const ContainerLayerParameters& aParameters) : 1.495 + mBuilder(aBuilder), mManager(aManager), 1.496 + mLayerBuilder(aLayerBuilder), 1.497 + mContainerFrame(aContainerFrame), 1.498 + mContainerLayer(aContainerLayer), 1.499 + mParameters(aParameters), 1.500 + mNextFreeRecycledThebesLayer(0) 1.501 + { 1.502 + nsPresContext* presContext = aContainerFrame->PresContext(); 1.503 + mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); 1.504 + mContainerReferenceFrame = aContainerItem ? aContainerItem->ReferenceFrameForChildren() : 1.505 + mBuilder->FindReferenceFrameFor(mContainerFrame); 1.506 + mContainerAnimatedGeometryRoot = aContainerItem 1.507 + ? nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder) 1.508 + : mContainerReferenceFrame; 1.509 + // When AllowResidualTranslation is false, display items will be drawn 1.510 + // scaled with a translation by integer pixels, so we know how the snapping 1.511 + // will work. 1.512 + mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() && 1.513 + !mParameters.AllowResidualTranslation(); 1.514 + CollectOldLayers(); 1.515 + } 1.516 + 1.517 + enum ProcessDisplayItemsFlags { 1.518 + NO_COMPONENT_ALPHA = 0x01, 1.519 + }; 1.520 + 1.521 + /** 1.522 + * This is the method that actually walks a display list and builds 1.523 + * the child layers. 1.524 + */ 1.525 + void ProcessDisplayItems(const nsDisplayList& aList, uint32_t aFlags); 1.526 + /** 1.527 + * This finalizes all the open ThebesLayers by popping every element off 1.528 + * mThebesLayerDataStack, then sets the children of the container layer 1.529 + * to be all the layers in mNewChildLayers in that order and removes any 1.530 + * layers as children of the container that aren't in mNewChildLayers. 1.531 + * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA, 1.532 + * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA 1.533 + */ 1.534 + void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData); 1.535 + 1.536 + nsRect GetChildrenBounds() { return mBounds; } 1.537 + 1.538 + nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; } 1.539 + 1.540 + nsIntRect ScaleToNearestPixels(const nsRect& aRect) 1.541 + { 1.542 + return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale, 1.543 + mAppUnitsPerDevPixel); 1.544 + } 1.545 + nsIntRegion ScaleRegionToNearestPixels(const nsRegion& aRegion) 1.546 + { 1.547 + return aRegion.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale, 1.548 + mAppUnitsPerDevPixel); 1.549 + } 1.550 + nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap = false) 1.551 + { 1.552 + if (aSnap && mSnappingEnabled) { 1.553 + return ScaleToNearestPixels(aRect); 1.554 + } 1.555 + return aRect.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale, 1.556 + mAppUnitsPerDevPixel); 1.557 + } 1.558 + nsIntRect ScaleToInsidePixels(const nsRect& aRect, bool aSnap = false) 1.559 + { 1.560 + if (aSnap && mSnappingEnabled) { 1.561 + return ScaleToNearestPixels(aRect); 1.562 + } 1.563 + return aRect.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale, 1.564 + mAppUnitsPerDevPixel); 1.565 + } 1.566 + 1.567 + nsIntRegion ScaleRegionToInsidePixels(const nsRegion& aRegion, bool aSnap = false) 1.568 + { 1.569 + if (aSnap && mSnappingEnabled) { 1.570 + return ScaleRegionToNearestPixels(aRegion); 1.571 + } 1.572 + return aRegion.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale, 1.573 + mAppUnitsPerDevPixel); 1.574 + } 1.575 + 1.576 + nsIntRegion ScaleRegionToOutsidePixels(const nsRegion& aRegion, bool aSnap = false) 1.577 + { 1.578 + if (aSnap && mSnappingEnabled) { 1.579 + return ScaleRegionToNearestPixels(aRegion); 1.580 + } 1.581 + return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale, 1.582 + mAppUnitsPerDevPixel); 1.583 + } 1.584 + 1.585 +protected: 1.586 + friend class ThebesLayerData; 1.587 + 1.588 + /** 1.589 + * Grab the next recyclable ThebesLayer, or create one if there are no 1.590 + * more recyclable ThebesLayers. Does any necessary invalidation of 1.591 + * a recycled ThebesLayer, and sets up the transform on the ThebesLayer 1.592 + * to account for scrolling. 1.593 + */ 1.594 + already_AddRefed<ThebesLayer> CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot, 1.595 + const nsIFrame *aReferenceFrame, 1.596 + const nsPoint& aTopLeft); 1.597 + /** 1.598 + * Grab the next recyclable ColorLayer, or create one if there are no 1.599 + * more recyclable ColorLayers. 1.600 + */ 1.601 + already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(ThebesLayer* aThebes); 1.602 + /** 1.603 + * Grab the next recyclable ImageLayer, or create one if there are no 1.604 + * more recyclable ImageLayers. 1.605 + */ 1.606 + already_AddRefed<ImageLayer> CreateOrRecycleImageLayer(ThebesLayer* aThebes); 1.607 + /** 1.608 + * Grab a recyclable ImageLayer for use as a mask layer for aLayer (that is a 1.609 + * mask layer which has been used for aLayer before), or create one if such 1.610 + * a layer doesn't exist. 1.611 + */ 1.612 + already_AddRefed<ImageLayer> CreateOrRecycleMaskImageLayerFor(Layer* aLayer); 1.613 + /** 1.614 + * Grabs all ThebesLayers and ColorLayers from the ContainerLayer and makes them 1.615 + * available for recycling. 1.616 + */ 1.617 + void CollectOldLayers(); 1.618 + /** 1.619 + * If aItem used to belong to a ThebesLayer, invalidates the area of 1.620 + * aItem in that layer. If aNewLayer is a ThebesLayer, invalidates the area of 1.621 + * aItem in that layer. 1.622 + */ 1.623 + void InvalidateForLayerChange(nsDisplayItem* aItem, 1.624 + Layer* aNewLayer, 1.625 + const DisplayItemClip& aClip, 1.626 + const nsPoint& aTopLeft, 1.627 + nsDisplayItemGeometry *aGeometry); 1.628 + /** 1.629 + * Try to determine whether the ThebesLayer at aThebesLayerIndex 1.630 + * has a single opaque color behind it, over the entire bounds of its visible 1.631 + * region. 1.632 + * If successful, return that color, otherwise return NS_RGBA(0,0,0,0). 1.633 + */ 1.634 + nscolor FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex); 1.635 + /** 1.636 + * Find the fixed-pos frame, if any, containing (or equal to) 1.637 + * aAnimatedGeometryRoot. Only return a fixed-pos frame if its viewport 1.638 + * has a displayport. Updates *aVisibleRegion to be the intersection of 1.639 + * aDrawRegion and the displayport, and updates *aIsSolidColorInVisibleRegion 1.640 + * (if non-null) to false if the visible region grows. 1.641 + * aDisplayItemFixedToViewport is true if the layer contains a single display 1.642 + * item which returned true for ShouldFixToViewport. 1.643 + * This can return the actual viewport frame for layers whose display items 1.644 + * are directly on the viewport (e.g. background-attachment:fixed backgrounds). 1.645 + */ 1.646 + const nsIFrame* FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot, 1.647 + bool aDisplayItemFixedToViewport); 1.648 + void AdjustLayerDataForFixedPositioning(const nsIFrame* aFixedPosFrame, 1.649 + const nsIntRegion& aDrawRegion, 1.650 + nsIntRegion* aVisibleRegion, 1.651 + bool* aIsSolidColorInVisibleRegion = nullptr); 1.652 + /** 1.653 + * Set fixed-pos layer metadata on aLayer according to the data for aFixedPosFrame. 1.654 + */ 1.655 + void SetFixedPositionLayerData(Layer* aLayer, 1.656 + const nsIFrame* aFixedPosFrame); 1.657 + /** 1.658 + * Indicate that we are done adding items to the ThebesLayer at the top of 1.659 + * mThebesLayerDataStack. Set the final visible region and opaque-content 1.660 + * flag, and pop it off the stack. 1.661 + */ 1.662 + void PopThebesLayerData(); 1.663 + /** 1.664 + * Find the ThebesLayer to which we should assign the next display item. 1.665 + * We scan the ThebesLayerData stack to find the topmost ThebesLayer 1.666 + * that is compatible with the display item (i.e., has the same 1.667 + * active scrolled root), and that has no content from other layers above 1.668 + * it and intersecting the aVisibleRect. 1.669 + * Returns the layer, and also updates the ThebesLayerData. Will 1.670 + * push a new ThebesLayerData onto the stack if no suitable existing 1.671 + * layer is found. If we choose a ThebesLayer that's already on the 1.672 + * ThebesLayerData stack, later elements on the stack will be popped off. 1.673 + * @param aVisibleRect the area of the next display item that's visible 1.674 + * @param aAnimatedGeometryRoot the active scrolled root for the next 1.675 + * display item 1.676 + * @param aOpaqueRect if non-null, a region of the display item that is opaque 1.677 + * @param aSolidColor if non-null, indicates that every pixel in aVisibleRect 1.678 + * will be painted with aSolidColor by the item 1.679 + * @param aShouldFixToViewport if true, aAnimatedGeometryRoot is the viewport 1.680 + * and we will be adding fixed-pos metadata for this layer because the 1.681 + * display item returned true from ShouldFixToViewport. 1.682 + */ 1.683 + ThebesLayerData* FindThebesLayerFor(nsDisplayItem* aItem, 1.684 + const nsIntRect& aVisibleRect, 1.685 + const nsIFrame* aAnimatedGeometryRoot, 1.686 + const nsPoint& aTopLeft, 1.687 + bool aShouldFixToViewport); 1.688 + ThebesLayerData* GetTopThebesLayerData() 1.689 + { 1.690 + return mThebesLayerDataStack.IsEmpty() ? nullptr 1.691 + : mThebesLayerDataStack[mThebesLayerDataStack.Length() - 1].get(); 1.692 + } 1.693 + 1.694 + /* Build a mask layer to represent the clipping region. Will return null if 1.695 + * there is no clipping specified or a mask layer cannot be built. 1.696 + * Builds an ImageLayer for the appropriate backend; the mask is relative to 1.697 + * aLayer's visible region. 1.698 + * aLayer is the layer to be clipped. 1.699 + * aRoundedRectClipCount is used when building mask layers for ThebesLayers, 1.700 + * SetupMaskLayer will build a mask layer for only the first 1.701 + * aRoundedRectClipCount rounded rects in aClip 1.702 + */ 1.703 + void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip, 1.704 + uint32_t aRoundedRectClipCount = UINT32_MAX); 1.705 + 1.706 + bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList, 1.707 + const nsIFrame **aAnimatedGeometryRoot); 1.708 + 1.709 + nsDisplayListBuilder* mBuilder; 1.710 + LayerManager* mManager; 1.711 + FrameLayerBuilder* mLayerBuilder; 1.712 + nsIFrame* mContainerFrame; 1.713 + const nsIFrame* mContainerReferenceFrame; 1.714 + const nsIFrame* mContainerAnimatedGeometryRoot; 1.715 + ContainerLayer* mContainerLayer; 1.716 + ContainerLayerParameters mParameters; 1.717 + /** 1.718 + * The region of ThebesLayers that should be invalidated every time 1.719 + * we recycle one. 1.720 + */ 1.721 + nsIntRegion mInvalidThebesContent; 1.722 + nsRect mBounds; 1.723 + nsAutoTArray<nsAutoPtr<ThebesLayerData>,1> mThebesLayerDataStack; 1.724 + /** 1.725 + * We collect the list of children in here. During ProcessDisplayItems, 1.726 + * the layers in this array either have mContainerLayer as their parent, 1.727 + * or no parent. 1.728 + */ 1.729 + typedef nsAutoTArray<nsRefPtr<Layer>,1> AutoLayersArray; 1.730 + AutoLayersArray mNewChildLayers; 1.731 + nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers; 1.732 + nsDataHashtable<nsPtrHashKey<Layer>, nsRefPtr<ImageLayer> > 1.733 + mRecycledMaskImageLayers; 1.734 + uint32_t mNextFreeRecycledThebesLayer; 1.735 + nscoord mAppUnitsPerDevPixel; 1.736 + bool mSnappingEnabled; 1.737 +}; 1.738 + 1.739 +class ThebesDisplayItemLayerUserData : public LayerUserData 1.740 +{ 1.741 +public: 1.742 + ThebesDisplayItemLayerUserData() : 1.743 + mMaskClipCount(0), 1.744 + mForcedBackgroundColor(NS_RGBA(0,0,0,0)), 1.745 + mXScale(1.f), mYScale(1.f), 1.746 + mAppUnitsPerDevPixel(0), 1.747 + mTranslation(0, 0), 1.748 + mAnimatedGeometryRootPosition(0, 0) {} 1.749 + 1.750 + /** 1.751 + * Record the number of clips in the Thebes layer's mask layer. 1.752 + * Should not be reset when the layer is recycled since it is used to track 1.753 + * changes in the use of mask layers. 1.754 + */ 1.755 + uint32_t mMaskClipCount; 1.756 + 1.757 + /** 1.758 + * A color that should be painted over the bounds of the layer's visible 1.759 + * region before any other content is painted. 1.760 + */ 1.761 + nscolor mForcedBackgroundColor; 1.762 + 1.763 + /** 1.764 + * The resolution scale used. 1.765 + */ 1.766 + float mXScale, mYScale; 1.767 + 1.768 + /** 1.769 + * The appunits per dev pixel for the items in this layer. 1.770 + */ 1.771 + nscoord mAppUnitsPerDevPixel; 1.772 + 1.773 + /** 1.774 + * The offset from the ThebesLayer's 0,0 to the 1.775 + * reference frame. This isn't necessarily the same as the transform 1.776 + * set on the ThebesLayer since we might also be applying an extra 1.777 + * offset specified by the parent ContainerLayer/ 1.778 + */ 1.779 + nsIntPoint mTranslation; 1.780 + 1.781 + /** 1.782 + * We try to make 0,0 of the ThebesLayer be the top-left of the 1.783 + * border-box of the "active scrolled root" frame (i.e. the nearest ancestor 1.784 + * frame for the display items that is being actively scrolled). But 1.785 + * we force the ThebesLayer transform to be an integer translation, and we may 1.786 + * have a resolution scale, so we have to snap the ThebesLayer transform, so 1.787 + * 0,0 may not be exactly the top-left of the active scrolled root. Here we 1.788 + * store the coordinates in ThebesLayer space of the top-left of the 1.789 + * active scrolled root. 1.790 + */ 1.791 + gfxPoint mAnimatedGeometryRootPosition; 1.792 + 1.793 + nsIntRegion mRegionToInvalidate; 1.794 + 1.795 + // The offset between the active scrolled root of this layer 1.796 + // and the root of the container for the previous and current 1.797 + // paints respectively. 1.798 + nsPoint mLastAnimatedGeometryRootOrigin; 1.799 + nsPoint mAnimatedGeometryRootOrigin; 1.800 + 1.801 + nsRefPtr<ColorLayer> mColorLayer; 1.802 + nsRefPtr<ImageLayer> mImageLayer; 1.803 +}; 1.804 + 1.805 +/* 1.806 + * User data for layers which will be used as masks. 1.807 + */ 1.808 +struct MaskLayerUserData : public LayerUserData 1.809 +{ 1.810 + MaskLayerUserData() 1.811 + : mScaleX(-1.0f) 1.812 + , mScaleY(-1.0f) 1.813 + , mAppUnitsPerDevPixel(-1) 1.814 + { } 1.815 + 1.816 + bool 1.817 + operator== (const MaskLayerUserData& aOther) const 1.818 + { 1.819 + return mRoundedClipRects == aOther.mRoundedClipRects && 1.820 + mScaleX == aOther.mScaleX && 1.821 + mScaleY == aOther.mScaleY && 1.822 + mOffset == aOther.mOffset && 1.823 + mAppUnitsPerDevPixel == aOther.mAppUnitsPerDevPixel; 1.824 + } 1.825 + 1.826 + nsRefPtr<const MaskLayerImageCache::MaskLayerImageKey> mImageKey; 1.827 + // properties of the mask layer; the mask layer may be re-used if these 1.828 + // remain unchanged. 1.829 + nsTArray<DisplayItemClip::RoundedRect> mRoundedClipRects; 1.830 + // scale from the masked layer which is applied to the mask 1.831 + float mScaleX, mScaleY; 1.832 + // The ContainerLayerParameters offset which is applied to the mask's transform. 1.833 + nsIntPoint mOffset; 1.834 + int32_t mAppUnitsPerDevPixel; 1.835 +}; 1.836 + 1.837 +/** 1.838 + * The address of gThebesDisplayItemLayerUserData is used as the user 1.839 + * data key for ThebesLayers created by FrameLayerBuilder. 1.840 + * It identifies ThebesLayers used to draw non-layer content, which are 1.841 + * therefore eligible for recycling. We want display items to be able to 1.842 + * create their own dedicated ThebesLayers in BuildLayer, if necessary, 1.843 + * and we wouldn't want to accidentally recycle those. 1.844 + * The user data is a ThebesDisplayItemLayerUserData. 1.845 + */ 1.846 +uint8_t gThebesDisplayItemLayerUserData; 1.847 +/** 1.848 + * The address of gColorLayerUserData is used as the user 1.849 + * data key for ColorLayers created by FrameLayerBuilder. 1.850 + * The user data is null. 1.851 + */ 1.852 +uint8_t gColorLayerUserData; 1.853 +/** 1.854 + * The address of gImageLayerUserData is used as the user 1.855 + * data key for ImageLayers created by FrameLayerBuilder. 1.856 + * The user data is null. 1.857 + */ 1.858 +uint8_t gImageLayerUserData; 1.859 +/** 1.860 + * The address of gLayerManagerUserData is used as the user 1.861 + * data key for retained LayerManagers managed by FrameLayerBuilder. 1.862 + * The user data is a LayerManagerData. 1.863 + */ 1.864 +uint8_t gLayerManagerUserData; 1.865 +/** 1.866 + * The address of gMaskLayerUserData is used as the user 1.867 + * data key for mask layers managed by FrameLayerBuilder. 1.868 + * The user data is a MaskLayerUserData. 1.869 + */ 1.870 +uint8_t gMaskLayerUserData; 1.871 + 1.872 +/** 1.873 + * Helper functions for getting user data and casting it to the correct type. 1.874 + * aLayer is the layer where the user data is stored. 1.875 + */ 1.876 +MaskLayerUserData* GetMaskLayerUserData(Layer* aLayer) 1.877 +{ 1.878 + return static_cast<MaskLayerUserData*>(aLayer->GetUserData(&gMaskLayerUserData)); 1.879 +} 1.880 + 1.881 +ThebesDisplayItemLayerUserData* GetThebesDisplayItemLayerUserData(Layer* aLayer) 1.882 +{ 1.883 + return static_cast<ThebesDisplayItemLayerUserData*>( 1.884 + aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); 1.885 +} 1.886 + 1.887 +/* static */ void 1.888 +FrameLayerBuilder::Shutdown() 1.889 +{ 1.890 + if (gMaskLayerImageCache) { 1.891 + delete gMaskLayerImageCache; 1.892 + gMaskLayerImageCache = nullptr; 1.893 + } 1.894 +} 1.895 + 1.896 +void 1.897 +FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager, 1.898 + ThebesLayerData* aLayerData) 1.899 +{ 1.900 + mDisplayListBuilder = aBuilder; 1.901 + mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext(); 1.902 + if (mRootPresContext) { 1.903 + mInitialDOMGeneration = mRootPresContext->GetDOMGeneration(); 1.904 + } 1.905 + mContainingThebesLayer = aLayerData; 1.906 + aManager->SetUserData(&gLayerManagerLayerBuilder, this); 1.907 +} 1.908 + 1.909 +void 1.910 +FrameLayerBuilder::FlashPaint(gfxContext *aContext) 1.911 +{ 1.912 + float r = float(rand()) / RAND_MAX; 1.913 + float g = float(rand()) / RAND_MAX; 1.914 + float b = float(rand()) / RAND_MAX; 1.915 + aContext->SetColor(gfxRGBA(r, g, b, 0.4)); 1.916 + aContext->Paint(); 1.917 +} 1.918 + 1.919 +FrameLayerBuilder::DisplayItemData* 1.920 +FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey) 1.921 +{ 1.922 + nsTArray<DisplayItemData*> *array = 1.923 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty())); 1.924 + if (array) { 1.925 + for (uint32_t i = 0; i < array->Length(); i++) { 1.926 + DisplayItemData* item = array->ElementAt(i); 1.927 + if (item->mDisplayItemKey == aKey && 1.928 + item->mLayer->Manager() == mRetainingManager) { 1.929 + return item; 1.930 + } 1.931 + } 1.932 + } 1.933 + return nullptr; 1.934 +} 1.935 + 1.936 +nsACString& 1.937 +AppendToString(nsACString& s, const nsIntRect& r, 1.938 + const char* pfx="", const char* sfx="") 1.939 +{ 1.940 + s += pfx; 1.941 + s += nsPrintfCString( 1.942 + "(x=%d, y=%d, w=%d, h=%d)", 1.943 + r.x, r.y, r.width, r.height); 1.944 + return s += sfx; 1.945 +} 1.946 + 1.947 +nsACString& 1.948 +AppendToString(nsACString& s, const nsIntRegion& r, 1.949 + const char* pfx="", const char* sfx="") 1.950 +{ 1.951 + s += pfx; 1.952 + 1.953 + nsIntRegionRectIterator it(r); 1.954 + s += "< "; 1.955 + while (const nsIntRect* sr = it.Next()) { 1.956 + AppendToString(s, *sr) += "; "; 1.957 + } 1.958 + s += ">"; 1.959 + 1.960 + return s += sfx; 1.961 +} 1.962 + 1.963 +/** 1.964 + * Invalidate aRegion in aLayer. aLayer is in the coordinate system 1.965 + * *after* aTranslation has been applied, so we need to 1.966 + * apply the inverse of that transform before calling InvalidateRegion. 1.967 + */ 1.968 +static void 1.969 +InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsIntRegion& aRegion, 1.970 + const nsIntPoint& aTranslation) 1.971 +{ 1.972 + // Convert the region from the coordinates of the container layer 1.973 + // (relative to the snapped top-left of the display list reference frame) 1.974 + // to the ThebesLayer's own coordinates 1.975 + nsIntRegion rgn = aRegion; 1.976 + rgn.MoveBy(-aTranslation); 1.977 + aLayer->InvalidateRegion(rgn); 1.978 +#ifdef MOZ_DUMP_PAINTING 1.979 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.980 + nsAutoCString str; 1.981 + AppendToString(str, rgn); 1.982 + printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get()); 1.983 + } 1.984 +#endif 1.985 +} 1.986 + 1.987 +static void 1.988 +InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsRect& aRect, 1.989 + const DisplayItemClip& aClip, 1.990 + const nsIntPoint& aTranslation) 1.991 +{ 1.992 + ThebesDisplayItemLayerUserData* data = 1.993 + static_cast<ThebesDisplayItemLayerUserData*>(aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); 1.994 + 1.995 + nsRect rect = aClip.ApplyNonRoundedIntersection(aRect); 1.996 + 1.997 + nsIntRect pixelRect = rect.ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel); 1.998 + InvalidatePostTransformRegion(aLayer, pixelRect, aTranslation); 1.999 +} 1.1000 + 1.1001 + 1.1002 +static nsIntPoint 1.1003 +GetTranslationForThebesLayer(ThebesLayer* aLayer) 1.1004 +{ 1.1005 + ThebesDisplayItemLayerUserData* data = 1.1006 + static_cast<ThebesDisplayItemLayerUserData*> 1.1007 + (aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); 1.1008 + NS_ASSERTION(data, "Must be a tracked thebes layer!"); 1.1009 + 1.1010 + return data->mTranslation; 1.1011 +} 1.1012 + 1.1013 +/** 1.1014 + * Some frames can have multiple, nested, retaining layer managers 1.1015 + * associated with them (normal manager, inactive managers, SVG effects). 1.1016 + * In these cases we store the 'outermost' LayerManager data property 1.1017 + * on the frame since we can walk down the chain from there. 1.1018 + * 1.1019 + * If one of these frames has just been destroyed, we will free the inner 1.1020 + * layer manager when removing the entry from mFramesWithLayers. Destroying 1.1021 + * the layer manager destroys the LayerManagerData and calls into 1.1022 + * the DisplayItemData destructor. If the inner layer manager had any 1.1023 + * items with the same frame, then we attempt to retrieve properties 1.1024 + * from the deleted frame. 1.1025 + * 1.1026 + * Cache the destroyed frame pointer here so we can avoid crashing in this case. 1.1027 + */ 1.1028 + 1.1029 +/* static */ void 1.1030 +FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame, 1.1031 + void* aPropertyValue) 1.1032 +{ 1.1033 + sDestroyedFrame = aFrame; 1.1034 + nsTArray<DisplayItemData*> *array = 1.1035 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aPropertyValue); 1.1036 + 1.1037 + // Hold a reference to all the items so that they don't get 1.1038 + // deleted from under us. 1.1039 + nsTArray<nsRefPtr<DisplayItemData> > arrayCopy; 1.1040 + for (uint32_t i = 0; i < array->Length(); ++i) { 1.1041 + arrayCopy.AppendElement(array->ElementAt(i)); 1.1042 + } 1.1043 + 1.1044 +#ifdef DEBUG_DISPLAY_ITEM_DATA 1.1045 + if (array->Length()) { 1.1046 + LayerManagerData *rootData = array->ElementAt(0)->mParent; 1.1047 + while (rootData->mParent) { 1.1048 + rootData = rootData->mParent; 1.1049 + } 1.1050 + printf_stderr("Removing frame %p - dumping display data\n", aFrame); 1.1051 + rootData->Dump(); 1.1052 + } 1.1053 +#endif 1.1054 + 1.1055 + for (uint32_t i = 0; i < array->Length(); ++i) { 1.1056 + DisplayItemData* data = array->ElementAt(i); 1.1057 + 1.1058 + ThebesLayer* t = data->mLayer->AsThebesLayer(); 1.1059 + if (t) { 1.1060 + ThebesDisplayItemLayerUserData* thebesData = 1.1061 + static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData)); 1.1062 + if (thebesData) { 1.1063 + nsRegion old = data->mGeometry->ComputeInvalidationRegion(); 1.1064 + nsIntRegion rgn = old.ScaleToOutsidePixels(thebesData->mXScale, thebesData->mYScale, thebesData->mAppUnitsPerDevPixel); 1.1065 + rgn.MoveBy(-GetTranslationForThebesLayer(t)); 1.1066 + thebesData->mRegionToInvalidate.Or(thebesData->mRegionToInvalidate, rgn); 1.1067 + thebesData->mRegionToInvalidate.SimplifyOutward(8); 1.1068 + } 1.1069 + } 1.1070 + 1.1071 + data->mParent->mDisplayItems.RemoveEntry(data); 1.1072 + } 1.1073 + 1.1074 + arrayCopy.Clear(); 1.1075 + delete array; 1.1076 + sDestroyedFrame = nullptr; 1.1077 +} 1.1078 + 1.1079 +void 1.1080 +FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager) 1.1081 +{ 1.1082 + mRetainingManager = aManager; 1.1083 + LayerManagerData* data = static_cast<LayerManagerData*> 1.1084 + (aManager->GetUserData(&gLayerManagerUserData)); 1.1085 + if (data) { 1.1086 + mInvalidateAllLayers = data->mInvalidateAllLayers; 1.1087 + } else { 1.1088 + data = new LayerManagerData(aManager); 1.1089 + aManager->SetUserData(&gLayerManagerUserData, data); 1.1090 + } 1.1091 +} 1.1092 + 1.1093 +void 1.1094 +FrameLayerBuilder::StoreOptimizedLayerForFrame(nsDisplayItem* aItem, Layer* aLayer) 1.1095 +{ 1.1096 + if (!mRetainingManager) { 1.1097 + return; 1.1098 + } 1.1099 + 1.1100 + DisplayItemData* data = GetDisplayItemDataForManager(aItem, aLayer->Manager()); 1.1101 + NS_ASSERTION(data, "Must have already stored data for this item!"); 1.1102 + data->mOptLayer = aLayer; 1.1103 +} 1.1104 + 1.1105 +void 1.1106 +FrameLayerBuilder::DidEndTransaction() 1.1107 +{ 1.1108 + GetMaskLayerImageCache()->Sweep(); 1.1109 +} 1.1110 + 1.1111 +void 1.1112 +FrameLayerBuilder::WillEndTransaction() 1.1113 +{ 1.1114 + if (!mRetainingManager) { 1.1115 + return; 1.1116 + } 1.1117 + 1.1118 + // We need to save the data we'll need to support retaining. 1.1119 + LayerManagerData* data = static_cast<LayerManagerData*> 1.1120 + (mRetainingManager->GetUserData(&gLayerManagerUserData)); 1.1121 + NS_ASSERTION(data, "Must have data!"); 1.1122 + // Update all the frames that used to have layers. 1.1123 + data->mDisplayItems.EnumerateEntries(ProcessRemovedDisplayItems, this); 1.1124 + data->mInvalidateAllLayers = false; 1.1125 +} 1.1126 + 1.1127 +/* static */ PLDHashOperator 1.1128 +FrameLayerBuilder::ProcessRemovedDisplayItems(nsRefPtrHashKey<DisplayItemData>* aEntry, 1.1129 + void* aUserArg) 1.1130 +{ 1.1131 + DisplayItemData* data = aEntry->GetKey(); 1.1132 + if (!data->mUsed) { 1.1133 + // This item was visible, but isn't anymore. 1.1134 + FrameLayerBuilder* layerBuilder = static_cast<FrameLayerBuilder*>(aUserArg); 1.1135 + 1.1136 + ThebesLayer* t = data->mLayer->AsThebesLayer(); 1.1137 + if (t) { 1.1138 +#ifdef MOZ_DUMP_PAINTING 1.1139 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.1140 + printf_stderr("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", data->mDisplayItemKey, data->mFrameList[0], t); 1.1141 + } 1.1142 +#endif 1.1143 + InvalidatePostTransformRegion(t, 1.1144 + data->mGeometry->ComputeInvalidationRegion(), 1.1145 + data->mClip, 1.1146 + layerBuilder->GetLastPaintOffset(t)); 1.1147 + } 1.1148 + return PL_DHASH_REMOVE; 1.1149 + } 1.1150 + 1.1151 + data->mUsed = false; 1.1152 + data->mIsInvalid = false; 1.1153 + return PL_DHASH_NEXT; 1.1154 +} 1.1155 + 1.1156 +/* static */ PLDHashOperator 1.1157 +FrameLayerBuilder::DumpDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>* aEntry, 1.1158 + void* aClosure) 1.1159 +{ 1.1160 +#ifdef DEBUG_DISPLAY_ITEM_DATA 1.1161 + DisplayItemData *data = aEntry->GetKey(); 1.1162 + 1.1163 + nsAutoCString prefix; 1.1164 + prefix += static_cast<const char*>(aClosure); 1.1165 + 1.1166 + const char *layerState; 1.1167 + switch (data->mLayerState) { 1.1168 + case LAYER_NONE: 1.1169 + layerState = "LAYER_NONE"; break; 1.1170 + case LAYER_INACTIVE: 1.1171 + layerState = "LAYER_INACTIVE"; break; 1.1172 + case LAYER_ACTIVE: 1.1173 + layerState = "LAYER_ACTIVE"; break; 1.1174 + case LAYER_ACTIVE_FORCE: 1.1175 + layerState = "LAYER_ACTIVE_FORCE"; break; 1.1176 + case LAYER_ACTIVE_EMPTY: 1.1177 + layerState = "LAYER_ACTIVE_EMPTY"; break; 1.1178 + case LAYER_SVG_EFFECTS: 1.1179 + layerState = "LAYER_SVG_EFFECTS"; break; 1.1180 + } 1.1181 + uint32_t mask = (1 << nsDisplayItem::TYPE_BITS) - 1; 1.1182 + 1.1183 + nsAutoCString str; 1.1184 + str += prefix; 1.1185 + str += nsPrintfCString("Frame %p ", data->mFrameList[0]); 1.1186 + str += nsDisplayItem::DisplayItemTypeName(static_cast<nsDisplayItem::Type>(data->mDisplayItemKey & mask)); 1.1187 + if ((data->mDisplayItemKey >> nsDisplayItem::TYPE_BITS)) { 1.1188 + str += nsPrintfCString("(%i)", data->mDisplayItemKey >> nsDisplayItem::TYPE_BITS); 1.1189 + } 1.1190 + str += nsPrintfCString(", %s, Layer %p", layerState, data->mLayer.get()); 1.1191 + if (data->mOptLayer) { 1.1192 + str += nsPrintfCString(", OptLayer %p", data->mOptLayer.get()); 1.1193 + } 1.1194 + if (data->mInactiveManager) { 1.1195 + str += nsPrintfCString(", InactiveLayerManager %p", data->mInactiveManager.get()); 1.1196 + } 1.1197 + str += "\n"; 1.1198 + 1.1199 + printf_stderr("%s", str.get()); 1.1200 + 1.1201 + if (data->mInactiveManager) { 1.1202 + prefix += " "; 1.1203 + printf_stderr("%sDumping inactive layer info:\n", prefix.get()); 1.1204 + LayerManagerData* lmd = static_cast<LayerManagerData*> 1.1205 + (data->mInactiveManager->GetUserData(&gLayerManagerUserData)); 1.1206 + lmd->Dump(prefix.get()); 1.1207 + } 1.1208 +#endif 1.1209 + return PL_DHASH_NEXT; 1.1210 +} 1.1211 + 1.1212 +/* static */ FrameLayerBuilder::DisplayItemData* 1.1213 +FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem, 1.1214 + LayerManager* aManager) 1.1215 +{ 1.1216 + nsTArray<DisplayItemData*> *array = 1.1217 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aItem->Frame()->Properties().Get(LayerManagerDataProperty())); 1.1218 + if (array) { 1.1219 + for (uint32_t i = 0; i < array->Length(); i++) { 1.1220 + DisplayItemData* item = array->ElementAt(i); 1.1221 + if (item->mDisplayItemKey == aItem->GetPerFrameKey() && 1.1222 + item->mLayer->Manager() == aManager) { 1.1223 + return item; 1.1224 + } 1.1225 + } 1.1226 + } 1.1227 + return nullptr; 1.1228 +} 1.1229 + 1.1230 +bool 1.1231 +FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) 1.1232 +{ 1.1233 + nsTArray<DisplayItemData*> *array = 1.1234 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty())); 1.1235 + if (array) { 1.1236 + for (uint32_t i = 0; i < array->Length(); i++) { 1.1237 + if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) { 1.1238 + return true; 1.1239 + } 1.1240 + } 1.1241 + } 1.1242 + return false; 1.1243 +} 1.1244 + 1.1245 +void 1.1246 +FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback) 1.1247 +{ 1.1248 + nsTArray<DisplayItemData*> *array = 1.1249 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty())); 1.1250 + if (!array) { 1.1251 + return; 1.1252 + } 1.1253 + 1.1254 + for (uint32_t i = 0; i < array->Length(); i++) { 1.1255 + DisplayItemData* data = array->ElementAt(i); 1.1256 + if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO) { 1.1257 + aCallback(aFrame, data); 1.1258 + } 1.1259 + } 1.1260 +} 1.1261 + 1.1262 +FrameLayerBuilder::DisplayItemData* 1.1263 +FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey) 1.1264 +{ 1.1265 + // If we need to build a new layer tree, then just refuse to recycle 1.1266 + // anything. 1.1267 + if (!mRetainingManager || mInvalidateAllLayers) 1.1268 + return nullptr; 1.1269 + 1.1270 + DisplayItemData *data = GetDisplayItemData(aFrame, aDisplayItemKey); 1.1271 + 1.1272 + if (data && data->mLayer->Manager() == mRetainingManager) { 1.1273 + return data; 1.1274 + } 1.1275 + return nullptr; 1.1276 +} 1.1277 + 1.1278 +Layer* 1.1279 +FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem, 1.1280 + nsDisplayItemGeometry** aOldGeometry, 1.1281 + DisplayItemClip** aOldClip, 1.1282 + nsTArray<nsIFrame*>* aChangedFrames, 1.1283 + bool *aIsInvalid) 1.1284 +{ 1.1285 + uint32_t key = aItem->GetPerFrameKey(); 1.1286 + nsIFrame* frame = aItem->Frame(); 1.1287 + 1.1288 + DisplayItemData* oldData = GetOldLayerForFrame(frame, key); 1.1289 + if (oldData) { 1.1290 + if (aOldGeometry) { 1.1291 + *aOldGeometry = oldData->mGeometry.get(); 1.1292 + } 1.1293 + if (aOldClip) { 1.1294 + *aOldClip = &oldData->mClip; 1.1295 + } 1.1296 + if (aChangedFrames) { 1.1297 + oldData->GetFrameListChanges(aItem, *aChangedFrames); 1.1298 + } 1.1299 + if (aIsInvalid) { 1.1300 + *aIsInvalid = oldData->mIsInvalid; 1.1301 + } 1.1302 + return oldData->mLayer; 1.1303 + } 1.1304 + 1.1305 + return nullptr; 1.1306 +} 1.1307 + 1.1308 +/* static */ Layer* 1.1309 +FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) 1.1310 +{ 1.1311 + nsTArray<DisplayItemData*> *array = 1.1312 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty())); 1.1313 + 1.1314 + if (!array) { 1.1315 + return nullptr; 1.1316 + } 1.1317 + 1.1318 + for (uint32_t i = 0; i < array->Length(); i++) { 1.1319 + DisplayItemData *data = array->ElementAt(i); 1.1320 + 1.1321 + if (data->mDisplayItemKey == aDisplayItemKey) { 1.1322 + return data->mLayer; 1.1323 + } 1.1324 + } 1.1325 + return nullptr; 1.1326 +} 1.1327 + 1.1328 +already_AddRefed<ColorLayer> 1.1329 +ContainerState::CreateOrRecycleColorLayer(ThebesLayer *aThebes) 1.1330 +{ 1.1331 + ThebesDisplayItemLayerUserData* data = 1.1332 + static_cast<ThebesDisplayItemLayerUserData*>(aThebes->GetUserData(&gThebesDisplayItemLayerUserData)); 1.1333 + nsRefPtr<ColorLayer> layer = data->mColorLayer; 1.1334 + if (layer) { 1.1335 + layer->SetMaskLayer(nullptr); 1.1336 + } else { 1.1337 + // Create a new layer 1.1338 + layer = mManager->CreateColorLayer(); 1.1339 + if (!layer) 1.1340 + return nullptr; 1.1341 + // Mark this layer as being used for Thebes-painting display items 1.1342 + data->mColorLayer = layer; 1.1343 + layer->SetUserData(&gColorLayerUserData, nullptr); 1.1344 + 1.1345 + // Remove other layer types we might have stored for this ThebesLayer 1.1346 + data->mImageLayer = nullptr; 1.1347 + } 1.1348 + return layer.forget(); 1.1349 +} 1.1350 + 1.1351 +already_AddRefed<ImageLayer> 1.1352 +ContainerState::CreateOrRecycleImageLayer(ThebesLayer *aThebes) 1.1353 +{ 1.1354 + ThebesDisplayItemLayerUserData* data = 1.1355 + static_cast<ThebesDisplayItemLayerUserData*>(aThebes->GetUserData(&gThebesDisplayItemLayerUserData)); 1.1356 + nsRefPtr<ImageLayer> layer = data->mImageLayer; 1.1357 + if (layer) { 1.1358 + layer->SetMaskLayer(nullptr); 1.1359 + } else { 1.1360 + // Create a new layer 1.1361 + layer = mManager->CreateImageLayer(); 1.1362 + if (!layer) 1.1363 + return nullptr; 1.1364 + // Mark this layer as being used for Thebes-painting display items 1.1365 + data->mImageLayer = layer; 1.1366 + layer->SetUserData(&gImageLayerUserData, nullptr); 1.1367 + 1.1368 + // Remove other layer types we might have stored for this ThebesLayer 1.1369 + data->mColorLayer = nullptr; 1.1370 + } 1.1371 + return layer.forget(); 1.1372 +} 1.1373 + 1.1374 +already_AddRefed<ImageLayer> 1.1375 +ContainerState::CreateOrRecycleMaskImageLayerFor(Layer* aLayer) 1.1376 +{ 1.1377 + nsRefPtr<ImageLayer> result = mRecycledMaskImageLayers.Get(aLayer); 1.1378 + if (result) { 1.1379 + mRecycledMaskImageLayers.Remove(aLayer); 1.1380 + // XXX if we use clip on mask layers, null it out here 1.1381 + } else { 1.1382 + // Create a new layer 1.1383 + result = mManager->CreateImageLayer(); 1.1384 + if (!result) 1.1385 + return nullptr; 1.1386 + result->SetUserData(&gMaskLayerUserData, new MaskLayerUserData()); 1.1387 + result->SetDisallowBigImage(true); 1.1388 + } 1.1389 + 1.1390 + return result.forget(); 1.1391 +} 1.1392 + 1.1393 +static const double SUBPIXEL_OFFSET_EPSILON = 0.02; 1.1394 + 1.1395 +/** 1.1396 + * This normally computes NSToIntRoundUp(aValue). However, if that would 1.1397 + * give a residual near 0.5 while aOldResidual is near -0.5, or 1.1398 + * it would give a residual near -0.5 while aOldResidual is near 0.5, then 1.1399 + * instead we return the integer in the other direction so that the residual 1.1400 + * is close to aOldResidual. 1.1401 + */ 1.1402 +static int32_t 1.1403 +RoundToMatchResidual(double aValue, double aOldResidual) 1.1404 +{ 1.1405 + int32_t v = NSToIntRoundUp(aValue); 1.1406 + double residual = aValue - v; 1.1407 + if (aOldResidual < 0) { 1.1408 + if (residual > 0 && fabs(residual - 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) { 1.1409 + // Round up instead 1.1410 + return int32_t(ceil(aValue)); 1.1411 + } 1.1412 + } else if (aOldResidual > 0) { 1.1413 + if (residual < 0 && fabs(residual + 1.0 - aOldResidual) < SUBPIXEL_OFFSET_EPSILON) { 1.1414 + // Round down instead 1.1415 + return int32_t(floor(aValue)); 1.1416 + } 1.1417 + } 1.1418 + return v; 1.1419 +} 1.1420 + 1.1421 +static void 1.1422 +ResetScrollPositionForLayerPixelAlignment(const nsIFrame* aAnimatedGeometryRoot) 1.1423 +{ 1.1424 + nsIScrollableFrame* sf = nsLayoutUtils::GetScrollableFrameFor(aAnimatedGeometryRoot); 1.1425 + if (sf) { 1.1426 + sf->ResetScrollPositionForLayerPixelAlignment(); 1.1427 + } 1.1428 +} 1.1429 + 1.1430 +static void 1.1431 +InvalidateEntireThebesLayer(ThebesLayer* aLayer, const nsIFrame* aAnimatedGeometryRoot) 1.1432 +{ 1.1433 +#ifdef MOZ_DUMP_PAINTING 1.1434 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.1435 + printf_stderr("Invalidating entire layer %p\n", aLayer); 1.1436 + } 1.1437 +#endif 1.1438 + nsIntRect invalidate = aLayer->GetValidRegion().GetBounds(); 1.1439 + aLayer->InvalidateRegion(invalidate); 1.1440 + aLayer->SetInvalidRectToVisibleRegion(); 1.1441 + ResetScrollPositionForLayerPixelAlignment(aAnimatedGeometryRoot); 1.1442 +} 1.1443 + 1.1444 +already_AddRefed<ThebesLayer> 1.1445 +ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot, 1.1446 + const nsIFrame* aReferenceFrame, 1.1447 + const nsPoint& aTopLeft) 1.1448 +{ 1.1449 + // We need a new thebes layer 1.1450 + nsRefPtr<ThebesLayer> layer; 1.1451 + ThebesDisplayItemLayerUserData* data; 1.1452 +#ifndef MOZ_ANDROID_OMTC 1.1453 + bool didResetScrollPositionForLayerPixelAlignment = false; 1.1454 +#endif 1.1455 + if (mNextFreeRecycledThebesLayer < mRecycledThebesLayers.Length()) { 1.1456 + // Recycle a layer 1.1457 + layer = mRecycledThebesLayers[mNextFreeRecycledThebesLayer]; 1.1458 + ++mNextFreeRecycledThebesLayer; 1.1459 + // Clear clip rect and mask layer so we don't accidentally stay clipped. 1.1460 + // We will reapply any necessary clipping. 1.1461 + layer->SetMaskLayer(nullptr); 1.1462 + 1.1463 + data = static_cast<ThebesDisplayItemLayerUserData*> 1.1464 + (layer->GetUserData(&gThebesDisplayItemLayerUserData)); 1.1465 + NS_ASSERTION(data, "Recycled ThebesLayers must have user data"); 1.1466 + 1.1467 + // This gets called on recycled ThebesLayers that are going to be in the 1.1468 + // final layer tree, so it's a convenient time to invalidate the 1.1469 + // content that changed where we don't know what ThebesLayer it belonged 1.1470 + // to, or if we need to invalidate the entire layer, we can do that. 1.1471 + // This needs to be done before we update the ThebesLayer to its new 1.1472 + // transform. See nsGfxScrollFrame::InvalidateInternal, where 1.1473 + // we ensure that mInvalidThebesContent is updated according to the 1.1474 + // scroll position as of the most recent paint. 1.1475 + if (!FuzzyEqual(data->mXScale, mParameters.mXScale, 0.00001f) || 1.1476 + !FuzzyEqual(data->mYScale, mParameters.mYScale, 0.00001f) || 1.1477 + data->mAppUnitsPerDevPixel != mAppUnitsPerDevPixel) { 1.1478 + InvalidateEntireThebesLayer(layer, aAnimatedGeometryRoot); 1.1479 +#ifndef MOZ_ANDROID_OMTC 1.1480 + didResetScrollPositionForLayerPixelAlignment = true; 1.1481 +#endif 1.1482 + } 1.1483 + if (!data->mRegionToInvalidate.IsEmpty()) { 1.1484 +#ifdef MOZ_DUMP_PAINTING 1.1485 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.1486 + printf_stderr("Invalidating deleted frame content from layer %p\n", layer.get()); 1.1487 + } 1.1488 +#endif 1.1489 + layer->InvalidateRegion(data->mRegionToInvalidate); 1.1490 +#ifdef MOZ_DUMP_PAINTING 1.1491 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.1492 + nsAutoCString str; 1.1493 + AppendToString(str, data->mRegionToInvalidate); 1.1494 + printf_stderr("Invalidating layer %p: %s\n", layer.get(), str.get()); 1.1495 + } 1.1496 +#endif 1.1497 + data->mRegionToInvalidate.SetEmpty(); 1.1498 + } 1.1499 + 1.1500 + // We do not need to Invalidate these areas in the widget because we 1.1501 + // assume the caller of InvalidateThebesLayerContents has ensured 1.1502 + // the area is invalidated in the widget. 1.1503 + } else { 1.1504 + // Check whether the layer will be scrollable. This is used as a hint to 1.1505 + // influence whether tiled layers are used or not. 1.1506 + bool canScroll = false; 1.1507 + nsIFrame* animatedGeometryRootParent = aAnimatedGeometryRoot->GetParent(); 1.1508 + if (animatedGeometryRootParent && 1.1509 + animatedGeometryRootParent->GetType() == nsGkAtoms::scrollFrame) { 1.1510 + canScroll = true; 1.1511 + } 1.1512 + // Create a new thebes layer 1.1513 + layer = mManager->CreateThebesLayerWithHint(canScroll ? LayerManager::SCROLLABLE : 1.1514 + LayerManager::NONE); 1.1515 + if (!layer) 1.1516 + return nullptr; 1.1517 + // Mark this layer as being used for Thebes-painting display items 1.1518 + data = new ThebesDisplayItemLayerUserData(); 1.1519 + layer->SetUserData(&gThebesDisplayItemLayerUserData, data); 1.1520 + ResetScrollPositionForLayerPixelAlignment(aAnimatedGeometryRoot); 1.1521 +#ifndef MOZ_ANDROID_OMTC 1.1522 + didResetScrollPositionForLayerPixelAlignment = true; 1.1523 +#endif 1.1524 + } 1.1525 + data->mXScale = mParameters.mXScale; 1.1526 + data->mYScale = mParameters.mYScale; 1.1527 + data->mLastAnimatedGeometryRootOrigin = data->mAnimatedGeometryRootOrigin; 1.1528 + data->mAnimatedGeometryRootOrigin = aTopLeft; 1.1529 + data->mAppUnitsPerDevPixel = mAppUnitsPerDevPixel; 1.1530 + layer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation()); 1.1531 + 1.1532 + mLayerBuilder->SaveLastPaintOffset(layer); 1.1533 + 1.1534 + // Set up transform so that 0,0 in the Thebes layer corresponds to the 1.1535 + // (pixel-snapped) top-left of the aAnimatedGeometryRoot. 1.1536 + nsPoint offset = aAnimatedGeometryRoot->GetOffsetToCrossDoc(aReferenceFrame); 1.1537 + nscoord appUnitsPerDevPixel = aAnimatedGeometryRoot->PresContext()->AppUnitsPerDevPixel(); 1.1538 + gfxPoint scaledOffset( 1.1539 + NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel)*mParameters.mXScale, 1.1540 + NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel)*mParameters.mYScale); 1.1541 + // We call RoundToMatchResidual here so that the residual after rounding 1.1542 + // is close to data->mAnimatedGeometryRootPosition if possible. 1.1543 + nsIntPoint pixOffset(RoundToMatchResidual(scaledOffset.x, data->mAnimatedGeometryRootPosition.x), 1.1544 + RoundToMatchResidual(scaledOffset.y, data->mAnimatedGeometryRootPosition.y)); 1.1545 + data->mTranslation = pixOffset; 1.1546 + pixOffset += mParameters.mOffset; 1.1547 + Matrix matrix; 1.1548 + matrix.Translate(pixOffset.x, pixOffset.y); 1.1549 + layer->SetBaseTransform(Matrix4x4::From2D(matrix)); 1.1550 + 1.1551 + // FIXME: Temporary workaround for bug 681192 and bug 724786. 1.1552 +#ifndef MOZ_ANDROID_OMTC 1.1553 + // Calculate exact position of the top-left of the active scrolled root. 1.1554 + // This might not be 0,0 due to the snapping in ScaleToNearestPixels. 1.1555 + gfxPoint animatedGeometryRootTopLeft = scaledOffset - ThebesPoint(matrix.GetTranslation()) + mParameters.mOffset; 1.1556 + // If it has changed, then we need to invalidate the entire layer since the 1.1557 + // pixels in the layer buffer have the content at a (subpixel) offset 1.1558 + // from what we need. 1.1559 + if (!animatedGeometryRootTopLeft.WithinEpsilonOf(data->mAnimatedGeometryRootPosition, SUBPIXEL_OFFSET_EPSILON)) { 1.1560 + data->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft; 1.1561 + InvalidateEntireThebesLayer(layer, aAnimatedGeometryRoot); 1.1562 + } else if (didResetScrollPositionForLayerPixelAlignment) { 1.1563 + data->mAnimatedGeometryRootPosition = animatedGeometryRootTopLeft; 1.1564 + } 1.1565 +#endif 1.1566 + 1.1567 + return layer.forget(); 1.1568 +} 1.1569 + 1.1570 +#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) 1.1571 +/** 1.1572 + * Returns the appunits per dev pixel for the item's frame 1.1573 + */ 1.1574 +static int32_t 1.1575 +AppUnitsPerDevPixel(nsDisplayItem* aItem) 1.1576 +{ 1.1577 + // The underlying frame for zoom items is the root frame of the subdocument. 1.1578 + // But zoom display items report their bounds etc using the parent document's 1.1579 + // APD because zoom items act as a conversion layer between the two different 1.1580 + // APDs. 1.1581 + if (aItem->GetType() == nsDisplayItem::TYPE_ZOOM) { 1.1582 + return static_cast<nsDisplayZoom*>(aItem)->GetParentAppUnitsPerDevPixel(); 1.1583 + } 1.1584 + return aItem->Frame()->PresContext()->AppUnitsPerDevPixel(); 1.1585 +} 1.1586 +#endif 1.1587 + 1.1588 +/** 1.1589 + * Restrict the visible region of aLayer to the region that is actually visible. 1.1590 + * Because we only reduce the visible region here, we don't need to worry 1.1591 + * about whether CONTENT_OPAQUE is set; if layer was opaque in the old 1.1592 + * visible region, it will still be opaque in the new one. 1.1593 + * @param aLayerVisibleRegion the visible region of the layer, in the layer's 1.1594 + * coordinate space 1.1595 + * @param aRestrictToRect the rect to restrict the visible region to, in the 1.1596 + * parent's coordinate system 1.1597 + */ 1.1598 +static void 1.1599 +SetVisibleRegionForLayer(Layer* aLayer, const nsIntRegion& aLayerVisibleRegion, 1.1600 + const nsIntRect& aRestrictToRect) 1.1601 +{ 1.1602 + gfx3DMatrix transform; 1.1603 + To3DMatrix(aLayer->GetTransform(), transform); 1.1604 + 1.1605 + // if 'transform' is not invertible, then nothing will be displayed 1.1606 + // for the layer, so it doesn't really matter what we do here 1.1607 + gfxRect itemVisible(aRestrictToRect.x, aRestrictToRect.y, 1.1608 + aRestrictToRect.width, aRestrictToRect.height); 1.1609 + nsIntRect childBounds = aLayerVisibleRegion.GetBounds(); 1.1610 + gfxRect childGfxBounds(childBounds.x, childBounds.y, 1.1611 + childBounds.width, childBounds.height); 1.1612 + gfxRect layerVisible = transform.UntransformBounds(itemVisible, childGfxBounds); 1.1613 + layerVisible.RoundOut(); 1.1614 + 1.1615 + nsIntRect visibleRect; 1.1616 + if (!gfxUtils::GfxRectToIntRect(layerVisible, &visibleRect)) { 1.1617 + aLayer->SetVisibleRegion(nsIntRegion()); 1.1618 + } else { 1.1619 + nsIntRegion rgn; 1.1620 + rgn.And(aLayerVisibleRegion, visibleRect); 1.1621 + aLayer->SetVisibleRegion(rgn); 1.1622 + } 1.1623 +} 1.1624 + 1.1625 +nscolor 1.1626 +ContainerState::FindOpaqueBackgroundColorFor(int32_t aThebesLayerIndex) 1.1627 +{ 1.1628 + ThebesLayerData* target = mThebesLayerDataStack[aThebesLayerIndex]; 1.1629 + for (int32_t i = aThebesLayerIndex - 1; i >= 0; --i) { 1.1630 + ThebesLayerData* candidate = mThebesLayerDataStack[i]; 1.1631 + if (candidate->IntersectsVisibleAboveRegion(target->mVisibleRegion)) { 1.1632 + // Some non-Thebes content between target and candidate; this is 1.1633 + // hopeless 1.1634 + break; 1.1635 + } 1.1636 + 1.1637 + nsIntRegion intersection; 1.1638 + intersection.And(candidate->mVisibleRegion, target->mVisibleRegion); 1.1639 + if (intersection.IsEmpty()) { 1.1640 + // The layer doesn't intersect our target, ignore it and move on 1.1641 + continue; 1.1642 + } 1.1643 + 1.1644 + // The candidate intersects our target. If any layer has a solid-color 1.1645 + // area behind our target, this must be it. Scan its display items. 1.1646 + nsIntRect deviceRect = target->mVisibleRegion.GetBounds(); 1.1647 + nsRect appUnitRect = deviceRect.ToAppUnits(mAppUnitsPerDevPixel); 1.1648 + appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale); 1.1649 + 1.1650 + FrameLayerBuilder::ThebesLayerItemsEntry* entry = 1.1651 + mLayerBuilder->GetThebesLayerItemsEntry(candidate->mLayer); 1.1652 + NS_ASSERTION(entry, "Must know about this layer!"); 1.1653 + for (int32_t j = entry->mItems.Length() - 1; j >= 0; --j) { 1.1654 + nsDisplayItem* item = entry->mItems[j].mItem; 1.1655 + bool snap; 1.1656 + nsRect bounds = item->GetBounds(mBuilder, &snap); 1.1657 + if (snap && mSnappingEnabled) { 1.1658 + nsIntRect snappedBounds = ScaleToNearestPixels(bounds); 1.1659 + if (!snappedBounds.Intersects(deviceRect)) 1.1660 + continue; 1.1661 + 1.1662 + if (!snappedBounds.Contains(deviceRect)) 1.1663 + break; 1.1664 + 1.1665 + } else { 1.1666 + // The layer's visible rect is already (close enough to) pixel 1.1667 + // aligned, so no need to round out and in here. 1.1668 + if (!bounds.Intersects(appUnitRect)) 1.1669 + continue; 1.1670 + 1.1671 + if (!bounds.Contains(appUnitRect)) 1.1672 + break; 1.1673 + } 1.1674 + 1.1675 + nscolor color; 1.1676 + if (item->IsUniform(mBuilder, &color) && NS_GET_A(color) == 255) 1.1677 + return color; 1.1678 + 1.1679 + break; 1.1680 + } 1.1681 + break; 1.1682 + } 1.1683 + return NS_RGBA(0,0,0,0); 1.1684 +} 1.1685 + 1.1686 +void 1.1687 +ThebesLayerData::UpdateCommonClipCount( 1.1688 + const DisplayItemClip& aCurrentClip) 1.1689 +{ 1.1690 + if (mCommonClipCount >= 0) { 1.1691 + mCommonClipCount = mItemClip.GetCommonRoundedRectCount(aCurrentClip, mCommonClipCount); 1.1692 + } else { 1.1693 + // first item in the layer 1.1694 + mCommonClipCount = aCurrentClip.GetRoundedRectCount(); 1.1695 + } 1.1696 +} 1.1697 + 1.1698 +already_AddRefed<ImageContainer> 1.1699 +ThebesLayerData::CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder) 1.1700 +{ 1.1701 + if (!mImage) { 1.1702 + return nullptr; 1.1703 + } 1.1704 + 1.1705 + return mImage->GetContainer(mLayer->Manager(), aBuilder); 1.1706 +} 1.1707 + 1.1708 +const nsIFrame* 1.1709 +ContainerState::FindFixedPosFrameForLayerData(const nsIFrame* aAnimatedGeometryRoot, 1.1710 + bool aDisplayItemFixedToViewport) 1.1711 +{ 1.1712 + if (!mManager->IsWidgetLayerManager()) { 1.1713 + // Never attach any fixed-pos metadata to inactive layers, it's pointless! 1.1714 + return nullptr; 1.1715 + } 1.1716 + 1.1717 + nsPresContext* presContext = mContainerFrame->PresContext(); 1.1718 + nsIFrame* viewport = presContext->PresShell()->GetRootFrame(); 1.1719 + 1.1720 + if (viewport == aAnimatedGeometryRoot && aDisplayItemFixedToViewport && 1.1721 + nsLayoutUtils::ViewportHasDisplayPort(presContext)) { 1.1722 + // Probably a background-attachment:fixed item 1.1723 + return viewport; 1.1724 + } 1.1725 + // Viewports with no fixed-pos frames are not relevant. 1.1726 + if (!viewport->GetFirstChild(nsIFrame::kFixedList)) { 1.1727 + return nullptr; 1.1728 + } 1.1729 + for (const nsIFrame* f = aAnimatedGeometryRoot; f; f = f->GetParent()) { 1.1730 + if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) { 1.1731 + return f; 1.1732 + } 1.1733 + if (f == mContainerReferenceFrame) { 1.1734 + // The metadata will go on an ancestor layer if necessary. 1.1735 + return nullptr; 1.1736 + } 1.1737 + } 1.1738 + return nullptr; 1.1739 +} 1.1740 + 1.1741 +void 1.1742 +ContainerState::AdjustLayerDataForFixedPositioning(const nsIFrame* aFixedPosFrame, 1.1743 + const nsIntRegion& aDrawRegion, 1.1744 + nsIntRegion* aVisibleRegion, 1.1745 + bool* aIsSolidColorInVisibleRegion) 1.1746 +{ 1.1747 + if (!aFixedPosFrame) { 1.1748 + return; 1.1749 + } 1.1750 + 1.1751 + nsRect fixedVisibleRect; 1.1752 + nsPresContext* presContext = aFixedPosFrame->PresContext(); 1.1753 + nsIPresShell* presShell = presContext->PresShell(); 1.1754 + DebugOnly<bool> hasDisplayPort = 1.1755 + nsLayoutUtils::ViewportHasDisplayPort(presContext, &fixedVisibleRect); 1.1756 + NS_ASSERTION(hasDisplayPort, "No fixed-pos layer data if there's no displayport"); 1.1757 + // Display ports are relative to the viewport, convert it to be relative 1.1758 + // to our reference frame. 1.1759 + nsIFrame* viewport = presShell->GetRootFrame(); 1.1760 + if (aFixedPosFrame != viewport) { 1.1761 + // position: fixed items are reflowed into and only drawn inside the 1.1762 + // viewport, or the scroll position clamping scrollport size, if one is 1.1763 + // set. We differentiate background-attachment: fixed items from 1.1764 + // position: fixed items by the fact that background-attachment: fixed 1.1765 + // items use the viewport as their aFixedPosFrame. 1.1766 + NS_ASSERTION(aFixedPosFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED, 1.1767 + "should be position fixed items only"); 1.1768 + fixedVisibleRect.MoveTo(0, 0); 1.1769 + if (presShell->IsScrollPositionClampingScrollPortSizeSet()) { 1.1770 + fixedVisibleRect.SizeTo(presShell->GetScrollPositionClampingScrollPortSize()); 1.1771 + } else { 1.1772 + fixedVisibleRect.SizeTo(viewport->GetSize()); 1.1773 + } 1.1774 + } 1.1775 + fixedVisibleRect += viewport->GetOffsetToCrossDoc(mContainerReferenceFrame); 1.1776 + nsIntRegion newVisibleRegion; 1.1777 + newVisibleRegion.And(ScaleToOutsidePixels(fixedVisibleRect, false), 1.1778 + aDrawRegion); 1.1779 + if (!aVisibleRegion->Contains(newVisibleRegion)) { 1.1780 + if (aIsSolidColorInVisibleRegion) { 1.1781 + *aIsSolidColorInVisibleRegion = false; 1.1782 + } 1.1783 + *aVisibleRegion = newVisibleRegion; 1.1784 + } 1.1785 +} 1.1786 + 1.1787 +void 1.1788 +ContainerState::SetFixedPositionLayerData(Layer* aLayer, 1.1789 + const nsIFrame* aFixedPosFrame) 1.1790 +{ 1.1791 + aLayer->SetIsFixedPosition(aFixedPosFrame != nullptr); 1.1792 + if (!aFixedPosFrame) { 1.1793 + return; 1.1794 + } 1.1795 + 1.1796 + nsPresContext* presContext = aFixedPosFrame->PresContext(); 1.1797 + 1.1798 + const nsIFrame* viewportFrame = aFixedPosFrame->GetParent(); 1.1799 + // anchorRect will be in the container's coordinate system (aLayer's parent layer). 1.1800 + // This is the same as the display items' reference frame. 1.1801 + nsRect anchorRect; 1.1802 + if (viewportFrame) { 1.1803 + // Fixed position frames are reflowed into the scroll-port size if one has 1.1804 + // been set. 1.1805 + if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) { 1.1806 + anchorRect.SizeTo(presContext->PresShell()->GetScrollPositionClampingScrollPortSize()); 1.1807 + } else { 1.1808 + anchorRect.SizeTo(viewportFrame->GetSize()); 1.1809 + } 1.1810 + } else { 1.1811 + // A display item directly attached to the viewport. 1.1812 + // For background-attachment:fixed items, the anchor point is always the 1.1813 + // top-left of the viewport currently. 1.1814 + viewportFrame = aFixedPosFrame; 1.1815 + } 1.1816 + // The anchorRect top-left is always the viewport top-left. 1.1817 + anchorRect.MoveTo(viewportFrame->GetOffsetToCrossDoc(mContainerReferenceFrame)); 1.1818 + 1.1819 + nsLayoutUtils::SetFixedPositionLayerData(aLayer, 1.1820 + viewportFrame, anchorRect, aFixedPosFrame, presContext, mParameters); 1.1821 +} 1.1822 + 1.1823 +static gfx3DMatrix 1.1824 +GetTransformToRoot(Layer* aLayer) 1.1825 +{ 1.1826 + Matrix4x4 transform = aLayer->GetTransform(); 1.1827 + for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) { 1.1828 + transform = transform * l->GetTransform(); 1.1829 + } 1.1830 + gfx3DMatrix result; 1.1831 + To3DMatrix(transform, result); 1.1832 + return result; 1.1833 +} 1.1834 + 1.1835 +static void 1.1836 +AddTransformedBoundsToRegion(const nsIntRegion& aRegion, 1.1837 + const gfx3DMatrix& aTransform, 1.1838 + nsIntRegion* aDest) 1.1839 +{ 1.1840 + nsIntRect bounds = aRegion.GetBounds(); 1.1841 + gfxRect transformed = 1.1842 + aTransform.TransformBounds(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)); 1.1843 + transformed.RoundOut(); 1.1844 + nsIntRect intRect; 1.1845 + if (!gfxUtils::GfxRectToIntRect(transformed, &intRect)) { 1.1846 + // This should only fail if coordinates are too big to fit in an int32 1.1847 + *aDest = nsIntRect(-INT32_MAX/2, -INT32_MAX/2, INT32_MAX, INT32_MAX); 1.1848 + return; 1.1849 + } 1.1850 + aDest->Or(*aDest, intRect); 1.1851 +} 1.1852 + 1.1853 +static bool 1.1854 +CanOptimizeAwayThebesLayer(ThebesLayerData* aData, 1.1855 + FrameLayerBuilder* aLayerBuilder) 1.1856 +{ 1.1857 + bool isRetained = aData->mLayer->Manager()->IsWidgetLayerManager(); 1.1858 + if (!isRetained) { 1.1859 + return false; 1.1860 + } 1.1861 + 1.1862 + // If there's no thebes layer with valid content in it that we can reuse, 1.1863 + // always create a color or image layer (and potentially throw away an 1.1864 + // existing completely invalid thebes layer). 1.1865 + if (aData->mLayer->GetValidRegion().IsEmpty()) { 1.1866 + return true; 1.1867 + } 1.1868 + 1.1869 + // There is an existing thebes layer we can reuse. Throwing it away can make 1.1870 + // compositing cheaper (see bug 946952), but it might cause us to re-allocate 1.1871 + // the thebes layer frequently due to an animation. So we only discard it if 1.1872 + // we're in tree compression mode, which is triggered at a low frequency. 1.1873 + return aLayerBuilder->CheckInLayerTreeCompressionMode(); 1.1874 +} 1.1875 + 1.1876 +void 1.1877 +ContainerState::PopThebesLayerData() 1.1878 +{ 1.1879 + NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop"); 1.1880 + 1.1881 + int32_t lastIndex = mThebesLayerDataStack.Length() - 1; 1.1882 + ThebesLayerData* data = mThebesLayerDataStack[lastIndex]; 1.1883 + 1.1884 + AdjustLayerDataForFixedPositioning(data->mFixedPosFrameForLayerData, 1.1885 + data->mDrawRegion, 1.1886 + &data->mVisibleRegion, 1.1887 + &data->mIsSolidColorInVisibleRegion); 1.1888 + nsRefPtr<Layer> layer; 1.1889 + nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder); 1.1890 + 1.1891 + if ((data->mIsSolidColorInVisibleRegion || imageContainer) && 1.1892 + CanOptimizeAwayThebesLayer(data, mLayerBuilder)) { 1.1893 + NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer), 1.1894 + "Can't be a solid color as well as an image!"); 1.1895 + if (imageContainer) { 1.1896 + nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer); 1.1897 + imageLayer->SetContainer(imageContainer); 1.1898 + data->mImage->ConfigureLayer(imageLayer, mParameters.mOffset); 1.1899 + imageLayer->SetPostScale(mParameters.mXScale, 1.1900 + mParameters.mYScale); 1.1901 + if (data->mItemClip.HasClip()) { 1.1902 + nsIntRect clip = ScaleToNearestPixels(data->mItemClip.GetClipRect()); 1.1903 + clip.MoveBy(mParameters.mOffset); 1.1904 + imageLayer->SetClipRect(&clip); 1.1905 + } else { 1.1906 + imageLayer->SetClipRect(nullptr); 1.1907 + } 1.1908 + layer = imageLayer; 1.1909 + mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage, 1.1910 + imageLayer); 1.1911 + } else { 1.1912 + nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer); 1.1913 + colorLayer->SetColor(data->mSolidColor); 1.1914 + 1.1915 + // Copy transform 1.1916 + colorLayer->SetBaseTransform(data->mLayer->GetBaseTransform()); 1.1917 + colorLayer->SetPostScale(data->mLayer->GetPostXScale(), data->mLayer->GetPostYScale()); 1.1918 + 1.1919 + nsIntRect visibleRect = data->mVisibleRegion.GetBounds(); 1.1920 + visibleRect.MoveBy(-GetTranslationForThebesLayer(data->mLayer)); 1.1921 + colorLayer->SetBounds(visibleRect); 1.1922 + 1.1923 + layer = colorLayer; 1.1924 + } 1.1925 + 1.1926 + NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???"); 1.1927 + AutoLayersArray::index_type index = mNewChildLayers.IndexOf(data->mLayer); 1.1928 + NS_ASSERTION(index != AutoLayersArray::NoIndex, "Thebes layer not found?"); 1.1929 + mNewChildLayers.InsertElementAt(index + 1, layer); 1.1930 + 1.1931 + // Hide the ThebesLayer. We leave it in the layer tree so that we 1.1932 + // can find and recycle it later. 1.1933 + nsIntRect emptyRect; 1.1934 + data->mLayer->SetClipRect(&emptyRect); 1.1935 + data->mLayer->SetVisibleRegion(nsIntRegion()); 1.1936 + data->mLayer->SetEventRegions(EventRegions()); 1.1937 + } else { 1.1938 + layer = data->mLayer; 1.1939 + imageContainer = nullptr; 1.1940 + layer->SetClipRect(nullptr); 1.1941 + } 1.1942 + 1.1943 + Matrix transform; 1.1944 + if (!layer->GetTransform().Is2D(&transform)) { 1.1945 + NS_ERROR("Only 2D transformations currently supported"); 1.1946 + } 1.1947 + 1.1948 + // ImageLayers are already configured with a visible region 1.1949 + if (!imageContainer) { 1.1950 + NS_ASSERTION(!transform.HasNonIntegerTranslation(), 1.1951 + "Matrix not just an integer translation?"); 1.1952 + // Convert from relative to the container to relative to the 1.1953 + // ThebesLayer itself. 1.1954 + nsIntRegion rgn = data->mVisibleRegion; 1.1955 + rgn.MoveBy(-GetTranslationForThebesLayer(data->mLayer)); 1.1956 + layer->SetVisibleRegion(rgn); 1.1957 + } 1.1958 + 1.1959 + nsIntRegion transparentRegion; 1.1960 + transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion); 1.1961 + bool isOpaque = transparentRegion.IsEmpty(); 1.1962 + // For translucent ThebesLayers, try to find an opaque background 1.1963 + // color that covers the entire area beneath it so we can pull that 1.1964 + // color into this layer to make it opaque. 1.1965 + if (layer == data->mLayer) { 1.1966 + nscolor backgroundColor = NS_RGBA(0,0,0,0); 1.1967 + if (!isOpaque) { 1.1968 + backgroundColor = FindOpaqueBackgroundColorFor(lastIndex); 1.1969 + if (NS_GET_A(backgroundColor) == 255) { 1.1970 + isOpaque = true; 1.1971 + } 1.1972 + } 1.1973 + 1.1974 + // Store the background color 1.1975 + ThebesDisplayItemLayerUserData* userData = 1.1976 + GetThebesDisplayItemLayerUserData(data->mLayer); 1.1977 + NS_ASSERTION(userData, "where did our user data go?"); 1.1978 + if (userData->mForcedBackgroundColor != backgroundColor) { 1.1979 + // Invalidate the entire target ThebesLayer since we're changing 1.1980 + // the background color 1.1981 + data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion()); 1.1982 + } 1.1983 + userData->mForcedBackgroundColor = backgroundColor; 1.1984 + 1.1985 + // use a mask layer for rounded rect clipping. 1.1986 + // data->mCommonClipCount may be -1 if we haven't put any actual 1.1987 + // drawable items in this layer (i.e. it's only catching events). 1.1988 + int32_t commonClipCount = std::max(0, data->mCommonClipCount); 1.1989 + SetupMaskLayer(layer, data->mItemClip, commonClipCount); 1.1990 + // copy commonClipCount to the entry 1.1991 + FrameLayerBuilder::ThebesLayerItemsEntry* entry = mLayerBuilder-> 1.1992 + GetThebesLayerItemsEntry(static_cast<ThebesLayer*>(layer.get())); 1.1993 + entry->mCommonClipCount = commonClipCount; 1.1994 + } else { 1.1995 + // mask layer for image and color layers 1.1996 + SetupMaskLayer(layer, data->mItemClip); 1.1997 + } 1.1998 + 1.1999 + uint32_t flags = 0; 1.2000 + nsIWidget* widget = mContainerReferenceFrame->PresContext()->GetRootWidget(); 1.2001 + // See bug 941095. Not quite ready to disable this. 1.2002 + bool hidpi = false && widget && widget->GetDefaultScale().scale >= 2; 1.2003 + if (hidpi) { 1.2004 + flags |= Layer::CONTENT_DISABLE_SUBPIXEL_AA; 1.2005 + } 1.2006 + if (isOpaque && !data->mForceTransparentSurface) { 1.2007 + flags |= Layer::CONTENT_OPAQUE; 1.2008 + } else if (data->mNeedComponentAlpha && !hidpi) { 1.2009 + flags |= Layer::CONTENT_COMPONENT_ALPHA; 1.2010 + } 1.2011 + layer->SetContentFlags(flags); 1.2012 + 1.2013 + SetFixedPositionLayerData(layer, data->mFixedPosFrameForLayerData); 1.2014 + 1.2015 + ThebesLayerData* containingThebesLayerData = 1.2016 + mLayerBuilder->GetContainingThebesLayerData(); 1.2017 + if (containingThebesLayerData) { 1.2018 + gfx3DMatrix matrix = GetTransformToRoot(layer); 1.2019 + nsIntPoint translatedDest = GetTranslationForThebesLayer(containingThebesLayerData->mLayer); 1.2020 + matrix.TranslatePost(-gfxPoint3D(translatedDest.x, translatedDest.y, 0)); 1.2021 + AddTransformedBoundsToRegion(data->mDispatchToContentHitRegion, matrix, 1.2022 + &containingThebesLayerData->mDispatchToContentHitRegion); 1.2023 + AddTransformedBoundsToRegion(data->mMaybeHitRegion, matrix, 1.2024 + &containingThebesLayerData->mMaybeHitRegion); 1.2025 + // Our definitely-hit region must go to the maybe-hit-region since 1.2026 + // this function is an approximation. 1.2027 + gfxMatrix matrix2D; 1.2028 + bool isPrecise = matrix.Is2D(&matrix2D) && !matrix2D.HasNonAxisAlignedTransform(); 1.2029 + AddTransformedBoundsToRegion(data->mHitRegion, matrix, 1.2030 + isPrecise ? &containingThebesLayerData->mHitRegion 1.2031 + : &containingThebesLayerData->mMaybeHitRegion); 1.2032 + } else { 1.2033 + EventRegions regions; 1.2034 + regions.mHitRegion.Swap(&data->mHitRegion); 1.2035 + // Points whose hit-region status we're not sure about need to be dispatched 1.2036 + // to the content thread. 1.2037 + regions.mDispatchToContentHitRegion.Sub(data->mMaybeHitRegion, regions.mHitRegion); 1.2038 + regions.mDispatchToContentHitRegion.Or(regions.mDispatchToContentHitRegion, 1.2039 + data->mDispatchToContentHitRegion); 1.2040 + layer->SetEventRegions(regions); 1.2041 + } 1.2042 + 1.2043 + if (lastIndex > 0) { 1.2044 + // Since we're going to pop off the last ThebesLayerData, the 1.2045 + // mVisibleAboveRegion of the second-to-last item will need to include 1.2046 + // the regions of the last item. 1.2047 + ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1]; 1.2048 + nextData->CopyAboveRegion(data); 1.2049 + } 1.2050 + 1.2051 + mThebesLayerDataStack.RemoveElementAt(lastIndex); 1.2052 +} 1.2053 + 1.2054 +static bool 1.2055 +SuppressComponentAlpha(nsDisplayListBuilder* aBuilder, 1.2056 + nsDisplayItem* aItem, 1.2057 + const nsRect& aComponentAlphaBounds) 1.2058 +{ 1.2059 + const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion(); 1.2060 + if (!windowTransparentRegion || windowTransparentRegion->IsEmpty()) 1.2061 + return false; 1.2062 + 1.2063 + // Suppress component alpha for items in the toplevel window that are over 1.2064 + // the window translucent area 1.2065 + nsIFrame* f = aItem->Frame(); 1.2066 + nsIFrame* ref = aBuilder->RootReferenceFrame(); 1.2067 + if (f->PresContext() != ref->PresContext()) 1.2068 + return false; 1.2069 + 1.2070 + for (nsIFrame* t = f; t; t = t->GetParent()) { 1.2071 + if (t->IsTransformed()) 1.2072 + return false; 1.2073 + } 1.2074 + 1.2075 + return windowTransparentRegion->Intersects(aComponentAlphaBounds); 1.2076 +} 1.2077 + 1.2078 +static bool 1.2079 +WindowHasTransparency(nsDisplayListBuilder* aBuilder) 1.2080 +{ 1.2081 + const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion(); 1.2082 + return windowTransparentRegion && !windowTransparentRegion->IsEmpty(); 1.2083 +} 1.2084 + 1.2085 +void 1.2086 +ThebesLayerData::Accumulate(ContainerState* aState, 1.2087 + nsDisplayItem* aItem, 1.2088 + const nsIntRect& aVisibleRect, 1.2089 + const nsIntRect& aDrawRect, 1.2090 + const DisplayItemClip& aClip) 1.2091 +{ 1.2092 + if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) { 1.2093 + mForceTransparentSurface = true; 1.2094 + } 1.2095 + if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) { 1.2096 + // Disable component alpha. 1.2097 + // Note that the transform (if any) on the ThebesLayer is always an integer translation so 1.2098 + // we don't have to factor that in here. 1.2099 + aItem->DisableComponentAlpha(); 1.2100 + } 1.2101 + 1.2102 + /* Mark as available for conversion to image layer if this is a nsDisplayImage and 1.2103 + * we are the first visible item in the ThebesLayerData object. 1.2104 + */ 1.2105 + if (mVisibleRegion.IsEmpty() && 1.2106 + aItem->SupportsOptimizingToImage()) { 1.2107 + mImage = static_cast<nsDisplayImageContainer*>(aItem); 1.2108 + } else { 1.2109 + mImage = nullptr; 1.2110 + } 1.2111 + bool clipMatches = mItemClip == aClip; 1.2112 + mItemClip = aClip; 1.2113 + 1.2114 + if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aDrawRect) && 1.2115 + mVisibleRegion.Contains(aVisibleRect)) { 1.2116 + // A very common case! Most pages have a ThebesLayer with the page 1.2117 + // background (opaque) visible and most or all of the page content over the 1.2118 + // top of that background. 1.2119 + // The rest of this method won't do anything. mVisibleRegion, mOpaqueRegion 1.2120 + // and mDrawRegion don't need updating. mVisibleRegion contains aVisibleRect 1.2121 + // already, mOpaqueRegion contains aDrawRect and therefore whatever 1.2122 + // the opaque region of the item is. mDrawRegion must contain mOpaqueRegion 1.2123 + // and therefore aDrawRect. 1.2124 + NS_ASSERTION(mDrawRegion.Contains(aDrawRect), "Draw region not covered"); 1.2125 + return; 1.2126 + } 1.2127 + 1.2128 + nscolor uniformColor; 1.2129 + bool isUniform = aItem->IsUniform(aState->mBuilder, &uniformColor); 1.2130 + 1.2131 + // Some display items have to exist (so they can set forceTransparentSurface 1.2132 + // below) but don't draw anything. They'll return true for isUniform but 1.2133 + // a color with opacity 0. 1.2134 + if (!isUniform || NS_GET_A(uniformColor) > 0) { 1.2135 + // Make sure that the visible area is covered by uniform pixels. In 1.2136 + // particular this excludes cases where the edges of the item are not 1.2137 + // pixel-aligned (thus the item will not be truly uniform). 1.2138 + if (isUniform) { 1.2139 + bool snap; 1.2140 + nsRect bounds = aItem->GetBounds(aState->mBuilder, &snap); 1.2141 + if (!aState->ScaleToInsidePixels(bounds, snap).Contains(aVisibleRect)) { 1.2142 + isUniform = false; 1.2143 + } 1.2144 + } 1.2145 + if (isUniform) { 1.2146 + if (mVisibleRegion.IsEmpty()) { 1.2147 + // This color is all we have 1.2148 + mSolidColor = uniformColor; 1.2149 + mIsSolidColorInVisibleRegion = true; 1.2150 + } else if (mIsSolidColorInVisibleRegion && 1.2151 + mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect)) && 1.2152 + clipMatches) { 1.2153 + // we can just blend the colors together 1.2154 + mSolidColor = NS_ComposeColors(mSolidColor, uniformColor); 1.2155 + } else { 1.2156 + mIsSolidColorInVisibleRegion = false; 1.2157 + } 1.2158 + } else { 1.2159 + mIsSolidColorInVisibleRegion = false; 1.2160 + } 1.2161 + 1.2162 + mVisibleRegion.Or(mVisibleRegion, aVisibleRect); 1.2163 + mVisibleRegion.SimplifyOutward(4); 1.2164 + mDrawRegion.Or(mDrawRegion, aDrawRect); 1.2165 + mDrawRegion.SimplifyOutward(4); 1.2166 + } 1.2167 + 1.2168 + bool snap; 1.2169 + nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap); 1.2170 + if (!opaque.IsEmpty()) { 1.2171 + nsRegion opaqueClipped; 1.2172 + nsRegionRectIterator iter(opaque); 1.2173 + for (const nsRect* r = iter.Next(); r; r = iter.Next()) { 1.2174 + opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInward(*r)); 1.2175 + } 1.2176 + 1.2177 + nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap); 1.2178 + 1.2179 + nsIntRegionRectIterator iter2(opaquePixels); 1.2180 + for (const nsIntRect* r = iter2.Next(); r; r = iter2.Next()) { 1.2181 + // We don't use SimplifyInward here since it's not defined exactly 1.2182 + // what it will discard. For our purposes the most important case 1.2183 + // is a large opaque background at the bottom of z-order (e.g., 1.2184 + // a canvas background), so we need to make sure that the first rect 1.2185 + // we see doesn't get discarded. 1.2186 + nsIntRegion tmp; 1.2187 + tmp.Or(mOpaqueRegion, *r); 1.2188 + // Opaque display items in chrome documents whose window is partially 1.2189 + // transparent are always added to the opaque region. This helps ensure 1.2190 + // that we get as much subpixel-AA as possible in the chrome. 1.2191 + if (tmp.GetNumRects() <= 4 || 1.2192 + (WindowHasTransparency(aState->mBuilder) && 1.2193 + aItem->Frame()->PresContext()->IsChrome())) { 1.2194 + mOpaqueRegion = tmp; 1.2195 + } 1.2196 + } 1.2197 + } 1.2198 + 1.2199 + if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants) { 1.2200 + nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder); 1.2201 + if (!componentAlpha.IsEmpty()) { 1.2202 + nsIntRect componentAlphaRect = 1.2203 + aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect); 1.2204 + if (!mOpaqueRegion.Contains(componentAlphaRect)) { 1.2205 + if (SuppressComponentAlpha(aState->mBuilder, aItem, componentAlpha)) { 1.2206 + aItem->DisableComponentAlpha(); 1.2207 + } else { 1.2208 + mNeedComponentAlpha = true; 1.2209 + } 1.2210 + } 1.2211 + } 1.2212 + } 1.2213 +} 1.2214 + 1.2215 +ThebesLayerData* 1.2216 +ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, 1.2217 + const nsIntRect& aVisibleRect, 1.2218 + const nsIFrame* aAnimatedGeometryRoot, 1.2219 + const nsPoint& aTopLeft, 1.2220 + bool aShouldFixToViewport) 1.2221 +{ 1.2222 + int32_t i; 1.2223 + int32_t lowestUsableLayerWithScrolledRoot = -1; 1.2224 + int32_t topmostLayerWithScrolledRoot = -1; 1.2225 + for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) { 1.2226 + // Don't let should-fix-to-viewport items share a layer with any other items. 1.2227 + if (aShouldFixToViewport) { 1.2228 + ++i; 1.2229 + break; 1.2230 + } 1.2231 + ThebesLayerData* data = mThebesLayerDataStack[i]; 1.2232 + // Give up if there is content drawn above (in z-order) this layer that 1.2233 + // intersects aItem's visible region; aItem must be placed in a 1.2234 + // layer this layer. 1.2235 + if (data->DrawAboveRegionIntersects(aVisibleRect)) { 1.2236 + ++i; 1.2237 + break; 1.2238 + } 1.2239 + // If the animated scrolled roots are the same and we can share this layer 1.2240 + // with the item, note this as a usable layer. 1.2241 + if (data->mAnimatedGeometryRoot == aAnimatedGeometryRoot && 1.2242 + !data->mSingleItemFixedToViewport) { 1.2243 + lowestUsableLayerWithScrolledRoot = i; 1.2244 + if (topmostLayerWithScrolledRoot < 0) { 1.2245 + topmostLayerWithScrolledRoot = i; 1.2246 + } 1.2247 + } 1.2248 + // If the layer's drawn region intersects the item, stop now since no 1.2249 + // lower layer will be usable. Do the same if the layer is subject to 1.2250 + // async transforms, since we don't know where it will really be drawn. 1.2251 + if (data->DrawRegionIntersects(aVisibleRect)) 1.2252 + break; 1.2253 + } 1.2254 + if (topmostLayerWithScrolledRoot < 0) { 1.2255 + --i; 1.2256 + for (; i >= 0; --i) { 1.2257 + ThebesLayerData* data = mThebesLayerDataStack[i]; 1.2258 + if (data->mAnimatedGeometryRoot == aAnimatedGeometryRoot) { 1.2259 + topmostLayerWithScrolledRoot = i; 1.2260 + break; 1.2261 + } 1.2262 + } 1.2263 + } 1.2264 + 1.2265 + if (topmostLayerWithScrolledRoot >= 0) { 1.2266 + while (uint32_t(topmostLayerWithScrolledRoot + 1) < mThebesLayerDataStack.Length()) { 1.2267 + PopThebesLayerData(); 1.2268 + } 1.2269 + } 1.2270 + 1.2271 + ThebesLayerData* thebesLayerData = nullptr; 1.2272 + if (lowestUsableLayerWithScrolledRoot < 0) { 1.2273 + nsRefPtr<ThebesLayer> layer = 1.2274 + CreateOrRecycleThebesLayer(aAnimatedGeometryRoot, aItem->ReferenceFrame(), aTopLeft); 1.2275 + 1.2276 + thebesLayerData = new ThebesLayerData(); 1.2277 + mThebesLayerDataStack.AppendElement(thebesLayerData); 1.2278 + thebesLayerData->mLayer = layer; 1.2279 + thebesLayerData->mAnimatedGeometryRoot = aAnimatedGeometryRoot; 1.2280 + thebesLayerData->mFixedPosFrameForLayerData = 1.2281 + FindFixedPosFrameForLayerData(aAnimatedGeometryRoot, aShouldFixToViewport); 1.2282 + thebesLayerData->mReferenceFrame = aItem->ReferenceFrame(); 1.2283 + thebesLayerData->mSingleItemFixedToViewport = aShouldFixToViewport; 1.2284 + 1.2285 + NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???"); 1.2286 + *mNewChildLayers.AppendElement() = layer.forget(); 1.2287 + } else { 1.2288 + thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot]; 1.2289 + } 1.2290 + 1.2291 + return thebesLayerData; 1.2292 +} 1.2293 + 1.2294 +#ifdef MOZ_DUMP_PAINTING 1.2295 +static void 1.2296 +DumpPaintedImage(nsDisplayItem* aItem, gfxASurface* aSurf) 1.2297 +{ 1.2298 + nsCString string(aItem->Name()); 1.2299 + string.Append("-"); 1.2300 + string.AppendInt((uint64_t)aItem); 1.2301 + fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading()); 1.2302 + aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile); 1.2303 + fprintf_stderr(gfxUtils::sDumpPaintFile, "\";"); 1.2304 +} 1.2305 +#endif 1.2306 + 1.2307 +static void 1.2308 +PaintInactiveLayer(nsDisplayListBuilder* aBuilder, 1.2309 + LayerManager* aManager, 1.2310 + nsDisplayItem* aItem, 1.2311 + gfxContext* aContext, 1.2312 + nsRenderingContext* aCtx) 1.2313 +{ 1.2314 + // This item has an inactive layer. Render it to a ThebesLayer 1.2315 + // using a temporary BasicLayerManager. 1.2316 + BasicLayerManager* basic = static_cast<BasicLayerManager*>(aManager); 1.2317 + nsRefPtr<gfxContext> context = aContext; 1.2318 +#ifdef MOZ_DUMP_PAINTING 1.2319 + int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem); 1.2320 + nsIntRect itemVisibleRect = 1.2321 + aItem->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel); 1.2322 + 1.2323 + nsRefPtr<gfxASurface> surf; 1.2324 + if (gfxUtils::sDumpPainting) { 1.2325 + surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size().ToIntSize(), 1.2326 + gfxContentType::COLOR_ALPHA); 1.2327 + surf->SetDeviceOffset(-itemVisibleRect.TopLeft()); 1.2328 + context = new gfxContext(surf); 1.2329 + } 1.2330 +#endif 1.2331 + basic->BeginTransaction(); 1.2332 + basic->SetTarget(context); 1.2333 + 1.2334 + if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) { 1.2335 + static_cast<nsDisplaySVGEffects*>(aItem)->PaintAsLayer(aBuilder, aCtx, basic); 1.2336 + if (basic->InTransaction()) { 1.2337 + basic->AbortTransaction(); 1.2338 + } 1.2339 + } else { 1.2340 + basic->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder); 1.2341 + } 1.2342 + FrameLayerBuilder *builder = static_cast<FrameLayerBuilder*>(basic->GetUserData(&gLayerManagerLayerBuilder)); 1.2343 + if (builder) { 1.2344 + builder->DidEndTransaction(); 1.2345 + } 1.2346 + 1.2347 + basic->SetTarget(nullptr); 1.2348 + 1.2349 +#ifdef MOZ_DUMP_PAINTING 1.2350 + if (gfxUtils::sDumpPainting) { 1.2351 + DumpPaintedImage(aItem, surf); 1.2352 + 1.2353 + surf->SetDeviceOffset(gfxPoint(0, 0)); 1.2354 + aContext->SetSource(surf, itemVisibleRect.TopLeft()); 1.2355 + aContext->Rectangle(itemVisibleRect); 1.2356 + aContext->Fill(); 1.2357 + aItem->SetPainted(); 1.2358 + } 1.2359 +#endif 1.2360 +} 1.2361 + 1.2362 +/** 1.2363 + * Chooses a single active scrolled root for the entire display list, used 1.2364 + * when we are flattening layers. 1.2365 + */ 1.2366 +bool 1.2367 +ContainerState::ChooseAnimatedGeometryRoot(const nsDisplayList& aList, 1.2368 + const nsIFrame **aAnimatedGeometryRoot) 1.2369 +{ 1.2370 + for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { 1.2371 + LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters); 1.2372 + // Don't use an item that won't be part of any ThebesLayers to pick the 1.2373 + // active scrolled root. 1.2374 + if (layerState == LAYER_ACTIVE_FORCE) { 1.2375 + continue; 1.2376 + } 1.2377 + 1.2378 + // Try using the actual active scrolled root of the backmost item, as that 1.2379 + // should result in the least invalidation when scrolling. 1.2380 + *aAnimatedGeometryRoot = 1.2381 + nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder); 1.2382 + return true; 1.2383 + } 1.2384 + return false; 1.2385 +} 1.2386 + 1.2387 +/* 1.2388 + * Iterate through the non-clip items in aList and its descendants. 1.2389 + * For each item we compute the effective clip rect. Each item is assigned 1.2390 + * to a layer. We invalidate the areas in ThebesLayers where an item 1.2391 + * has moved from one ThebesLayer to another. Also, 1.2392 + * aState->mInvalidThebesContent is invalidated in every ThebesLayer. 1.2393 + * We set the clip rect for items that generated their own layer, and 1.2394 + * create a mask layer to do any rounded rect clipping. 1.2395 + * (ThebesLayers don't need a clip rect on the layer, we clip the items 1.2396 + * individually when we draw them.) 1.2397 + * We set the visible rect for all layers, although the actual setting 1.2398 + * of visible rects for some ThebesLayers is deferred until the calling 1.2399 + * of ContainerState::Finish. 1.2400 + */ 1.2401 +void 1.2402 +ContainerState::ProcessDisplayItems(const nsDisplayList& aList, 1.2403 + uint32_t aFlags) 1.2404 +{ 1.2405 + PROFILER_LABEL("ContainerState", "ProcessDisplayItems"); 1.2406 + 1.2407 + const nsIFrame* lastAnimatedGeometryRoot = mContainerReferenceFrame; 1.2408 + nsPoint topLeft(0,0); 1.2409 + 1.2410 + // When NO_COMPONENT_ALPHA is set, items will be flattened into a single 1.2411 + // layer, so we need to choose which active scrolled root to use for all 1.2412 + // items. 1.2413 + if (aFlags & NO_COMPONENT_ALPHA) { 1.2414 + if (ChooseAnimatedGeometryRoot(aList, &lastAnimatedGeometryRoot)) { 1.2415 + topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame); 1.2416 + } 1.2417 + } 1.2418 + 1.2419 + int32_t maxLayers = nsDisplayItem::MaxActiveLayers(); 1.2420 + int layerCount = 0; 1.2421 + 1.2422 + for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { 1.2423 + NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item), 1.2424 + "items in a container layer should all have the same app units per dev pixel"); 1.2425 + 1.2426 + nsIntRect itemVisibleRect = 1.2427 + ScaleToOutsidePixels(item->GetVisibleRect(), false); 1.2428 + bool snap; 1.2429 + nsRect itemContent = item->GetBounds(mBuilder, &snap); 1.2430 + nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap); 1.2431 + nsDisplayItem::Type itemType = item->GetType(); 1.2432 + nsIntRect clipRect; 1.2433 + const DisplayItemClip& itemClip = item->GetClip(); 1.2434 + if (itemClip.HasClip()) { 1.2435 + itemContent.IntersectRect(itemContent, itemClip.GetClipRect()); 1.2436 + clipRect = ScaleToNearestPixels(itemClip.GetClipRect()); 1.2437 + itemDrawRect.IntersectRect(itemDrawRect, clipRect); 1.2438 + clipRect.MoveBy(mParameters.mOffset); 1.2439 + } 1.2440 + mBounds.UnionRect(mBounds, itemContent); 1.2441 + itemVisibleRect.IntersectRect(itemVisibleRect, itemDrawRect); 1.2442 + 1.2443 + LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters); 1.2444 + if (layerState == LAYER_INACTIVE && 1.2445 + nsDisplayItem::ForceActiveLayers()) { 1.2446 + layerState = LAYER_ACTIVE; 1.2447 + } 1.2448 + 1.2449 + bool forceInactive; 1.2450 + const nsIFrame* animatedGeometryRoot; 1.2451 + if (aFlags & NO_COMPONENT_ALPHA) { 1.2452 + forceInactive = true; 1.2453 + animatedGeometryRoot = lastAnimatedGeometryRoot; 1.2454 + } else { 1.2455 + forceInactive = false; 1.2456 + if (mManager->IsWidgetLayerManager()) { 1.2457 + animatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder); 1.2458 + } else { 1.2459 + // For inactive layer subtrees, splitting content into ThebesLayers 1.2460 + // based on animated geometry roots is pointless. It's more efficient 1.2461 + // to build the minimum number of layers. 1.2462 + animatedGeometryRoot = mContainerAnimatedGeometryRoot; 1.2463 + } 1.2464 + if (animatedGeometryRoot != lastAnimatedGeometryRoot) { 1.2465 + lastAnimatedGeometryRoot = animatedGeometryRoot; 1.2466 + topLeft = animatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame); 1.2467 + } 1.2468 + } 1.2469 + bool shouldFixToViewport = !animatedGeometryRoot->GetParent() && 1.2470 + item->ShouldFixToViewport(mBuilder); 1.2471 + 1.2472 + if (maxLayers != -1 && layerCount >= maxLayers) { 1.2473 + forceInactive = true; 1.2474 + } 1.2475 + 1.2476 + // Assign the item to a layer 1.2477 + if (layerState == LAYER_ACTIVE_FORCE || 1.2478 + (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) || 1.2479 + (!forceInactive && 1.2480 + (layerState == LAYER_ACTIVE_EMPTY || 1.2481 + layerState == LAYER_ACTIVE))) { 1.2482 + 1.2483 + layerCount++; 1.2484 + 1.2485 + // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata. 1.2486 + // We should never see an empty layer with any visible content! 1.2487 + NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY || 1.2488 + itemVisibleRect.IsEmpty(), 1.2489 + "State is LAYER_ACTIVE_EMPTY but visible rect is not."); 1.2490 + 1.2491 + // As long as the new layer isn't going to be a ThebesLayer, 1.2492 + // InvalidateForLayerChange doesn't need the new layer pointer. 1.2493 + // We also need to check the old data now, because BuildLayer 1.2494 + // can overwrite it. 1.2495 + InvalidateForLayerChange(item, nullptr, itemClip, topLeft, nullptr); 1.2496 + 1.2497 + // If the item would have its own layer but is invisible, just hide it. 1.2498 + // Note that items without their own layers can't be skipped this 1.2499 + // way, since their ThebesLayer may decide it wants to draw them 1.2500 + // into its buffer even if they're currently covered. 1.2501 + if (itemVisibleRect.IsEmpty() && 1.2502 + !item->ShouldBuildLayerEvenIfInvisible(mBuilder)) { 1.2503 + continue; 1.2504 + } 1.2505 + 1.2506 + if (itemType == nsDisplayItem::TYPE_TRANSFORM) { 1.2507 + mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr; 1.2508 + } else { 1.2509 + mParameters.mAncestorClipRect = nullptr; 1.2510 + } 1.2511 + 1.2512 + // Just use its layer. 1.2513 + nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters); 1.2514 + if (!ownLayer) { 1.2515 + continue; 1.2516 + } 1.2517 + 1.2518 + NS_ASSERTION(!ownLayer->AsThebesLayer(), 1.2519 + "Should never have created a dedicated Thebes layer!"); 1.2520 + 1.2521 + const nsIFrame* fixedPosFrame = 1.2522 + FindFixedPosFrameForLayerData(animatedGeometryRoot, shouldFixToViewport); 1.2523 + if (fixedPosFrame) { 1.2524 + nsIntRegion visibleRegion(itemVisibleRect); 1.2525 + AdjustLayerDataForFixedPositioning(fixedPosFrame, 1.2526 + nsIntRegion(itemDrawRect), &visibleRegion); 1.2527 + itemVisibleRect = visibleRegion.GetBounds(); 1.2528 + } 1.2529 + SetFixedPositionLayerData(ownLayer, fixedPosFrame); 1.2530 + 1.2531 + nsRect invalid; 1.2532 + if (item->IsInvalid(invalid)) { 1.2533 + ownLayer->SetInvalidRectToVisibleRegion(); 1.2534 + } 1.2535 + 1.2536 + // If it's not a ContainerLayer, we need to apply the scale transform 1.2537 + // ourselves. 1.2538 + if (!ownLayer->AsContainerLayer()) { 1.2539 + ownLayer->SetPostScale(mParameters.mXScale, 1.2540 + mParameters.mYScale); 1.2541 + } 1.2542 + 1.2543 + // Update that layer's clip and visible rects. 1.2544 + NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager"); 1.2545 + NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData), 1.2546 + "We shouldn't have a FrameLayerBuilder-managed layer here!"); 1.2547 + NS_ASSERTION(itemClip.HasClip() || 1.2548 + itemClip.GetRoundedRectCount() == 0, 1.2549 + "If we have rounded rects, we must have a clip rect"); 1.2550 + // It has its own layer. Update that layer's clip and visible rects. 1.2551 + if (itemClip.HasClip()) { 1.2552 + ownLayer->SetClipRect(&clipRect); 1.2553 + } else { 1.2554 + ownLayer->SetClipRect(nullptr); 1.2555 + } 1.2556 + ThebesLayerData* data = GetTopThebesLayerData(); 1.2557 + if (data) { 1.2558 + // Prerendered transform items can be updated without layer building 1.2559 + // (async animations or an empty transaction), so we treat all other 1.2560 + // content as being above this so that the transformed layer can correctly 1.2561 + // move behind other content. 1.2562 + if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM && 1.2563 + nsDisplayTransform::ShouldPrerenderTransformedContent(mBuilder, 1.2564 + item->Frame(), 1.2565 + false)) { 1.2566 + data->SetAllDrawingAbove(); 1.2567 + } else { 1.2568 + data->AddVisibleAboveRegion(itemVisibleRect); 1.2569 + 1.2570 + // Add the entire bounds rect to the mDrawAboveRegion. 1.2571 + // The visible region may be excluding opaque content above the 1.2572 + // item, and we need to ensure that that content is not placed 1.2573 + // in a ThebesLayer below the item! 1.2574 + data->AddDrawAboveRegion(itemDrawRect); 1.2575 + } 1.2576 + } 1.2577 + itemVisibleRect.MoveBy(mParameters.mOffset); 1.2578 + if (item->SetVisibleRegionOnLayer()) { 1.2579 + SetVisibleRegionForLayer(ownLayer, ownLayer->GetVisibleRegion(), itemVisibleRect); 1.2580 + } 1.2581 + 1.2582 + // rounded rectangle clipping using mask layers 1.2583 + // (must be done after visible rect is set on layer) 1.2584 + if (itemClip.IsRectClippedByRoundedCorner(itemContent)) { 1.2585 + SetupMaskLayer(ownLayer, itemClip); 1.2586 + } 1.2587 + 1.2588 + ContainerLayer* oldContainer = ownLayer->GetParent(); 1.2589 + if (oldContainer && oldContainer != mContainerLayer) { 1.2590 + oldContainer->RemoveChild(ownLayer); 1.2591 + } 1.2592 + NS_ASSERTION(!mNewChildLayers.Contains(ownLayer), 1.2593 + "Layer already in list???"); 1.2594 + 1.2595 + mNewChildLayers.AppendElement(ownLayer); 1.2596 + 1.2597 + /** 1.2598 + * No need to allocate geometry for items that aren't 1.2599 + * part of a ThebesLayer. 1.2600 + */ 1.2601 + nsAutoPtr<nsDisplayItemGeometry> dummy; 1.2602 + mLayerBuilder->AddLayerDisplayItem(ownLayer, item, 1.2603 + itemClip, layerState, 1.2604 + topLeft, nullptr, 1.2605 + dummy); 1.2606 + } else { 1.2607 + ThebesLayerData* data = 1.2608 + FindThebesLayerFor(item, itemVisibleRect, animatedGeometryRoot, topLeft, 1.2609 + shouldFixToViewport); 1.2610 + 1.2611 + if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) { 1.2612 + nsDisplayLayerEventRegions* eventRegions = 1.2613 + static_cast<nsDisplayLayerEventRegions*>(item); 1.2614 + data->AccumulateEventRegions(ScaleRegionToOutsidePixels(eventRegions->HitRegion()), 1.2615 + ScaleRegionToOutsidePixels(eventRegions->MaybeHitRegion()), 1.2616 + ScaleRegionToOutsidePixels(eventRegions->DispatchToContentHitRegion())); 1.2617 + } else { 1.2618 + // check to see if the new item has rounded rect clips in common with 1.2619 + // other items in the layer 1.2620 + data->UpdateCommonClipCount(itemClip); 1.2621 + data->Accumulate(this, item, itemVisibleRect, itemDrawRect, itemClip); 1.2622 + 1.2623 + nsAutoPtr<nsDisplayItemGeometry> geometry(item->AllocateGeometry(mBuilder)); 1.2624 + InvalidateForLayerChange(item, data->mLayer, itemClip, topLeft, geometry); 1.2625 + 1.2626 + mLayerBuilder->AddThebesDisplayItem(data, item, itemClip, 1.2627 + mContainerFrame, 1.2628 + layerState, topLeft, 1.2629 + geometry); 1.2630 + } 1.2631 + } 1.2632 + } 1.2633 +} 1.2634 + 1.2635 +void 1.2636 +ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, 1.2637 + Layer* aNewLayer, 1.2638 + const DisplayItemClip& aClip, 1.2639 + const nsPoint& aTopLeft, 1.2640 + nsDisplayItemGeometry *aGeometry) 1.2641 +{ 1.2642 + NS_ASSERTION(aItem->GetPerFrameKey(), 1.2643 + "Display items that render using Thebes must have a key"); 1.2644 + nsDisplayItemGeometry *oldGeometry = nullptr; 1.2645 + DisplayItemClip* oldClip = nullptr; 1.2646 + nsAutoTArray<nsIFrame*,4> changedFrames; 1.2647 + bool isInvalid = false; 1.2648 + Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip, &changedFrames, &isInvalid); 1.2649 + if (aNewLayer != oldLayer && oldLayer) { 1.2650 + // The item has changed layers. 1.2651 + // Invalidate the old bounds in the old layer and new bounds in the new layer. 1.2652 + ThebesLayer* t = oldLayer->AsThebesLayer(); 1.2653 + if (t) { 1.2654 + // Note that whenever the layer's scale changes, we invalidate the whole thing, 1.2655 + // so it doesn't matter whether we are using the old scale at last paint 1.2656 + // or a new scale here 1.2657 +#ifdef MOZ_DUMP_PAINTING 1.2658 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.2659 + printf_stderr("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), aItem->Frame(), t, aNewLayer); 1.2660 + } 1.2661 +#endif 1.2662 + InvalidatePostTransformRegion(t, 1.2663 + oldGeometry->ComputeInvalidationRegion(), 1.2664 + *oldClip, 1.2665 + mLayerBuilder->GetLastPaintOffset(t)); 1.2666 + } 1.2667 + if (aNewLayer) { 1.2668 + ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer(); 1.2669 + if (newThebesLayer) { 1.2670 + InvalidatePostTransformRegion(newThebesLayer, 1.2671 + aGeometry->ComputeInvalidationRegion(), 1.2672 + aClip, 1.2673 + GetTranslationForThebesLayer(newThebesLayer)); 1.2674 + } 1.2675 + } 1.2676 + aItem->NotifyRenderingChanged(); 1.2677 + return; 1.2678 + } 1.2679 + if (!aNewLayer) { 1.2680 + return; 1.2681 + } 1.2682 + 1.2683 + ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer(); 1.2684 + if (!newThebesLayer) { 1.2685 + return; 1.2686 + } 1.2687 + 1.2688 + ThebesDisplayItemLayerUserData* data = 1.2689 + static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData)); 1.2690 + // If the frame is marked as invalidated, and didn't specify a rect to invalidate then we want to 1.2691 + // invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas. 1.2692 + // If we do get an invalid rect, then we want to add this on top of the change areas. 1.2693 + nsRect invalid; 1.2694 + nsRegion combined; 1.2695 + nsPoint shift = aTopLeft - data->mLastAnimatedGeometryRootOrigin; 1.2696 + bool notifyRenderingChanged = true; 1.2697 + if (!oldLayer) { 1.2698 + // This item is being added for the first time, invalidate its entire area. 1.2699 + //TODO: We call GetGeometry again in AddThebesDisplayItem, we should reuse this. 1.2700 + combined = aClip.ApplyNonRoundedIntersection(aGeometry->ComputeInvalidationRegion()); 1.2701 +#ifdef MOZ_DUMP_PAINTING 1.2702 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.2703 + printf_stderr("Display item type %s(%p) added to layer %p!\n", aItem->Name(), aItem->Frame(), aNewLayer); 1.2704 + } 1.2705 +#endif 1.2706 + } else if (isInvalid || (aItem->IsInvalid(invalid) && invalid.IsEmpty())) { 1.2707 + // Either layout marked item as needing repainting, invalidate the entire old and new areas. 1.2708 + combined = oldClip->ApplyNonRoundedIntersection(oldGeometry->ComputeInvalidationRegion()); 1.2709 + combined.MoveBy(shift); 1.2710 + combined.Or(combined, aClip.ApplyNonRoundedIntersection(aGeometry->ComputeInvalidationRegion())); 1.2711 +#ifdef MOZ_DUMP_PAINTING 1.2712 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.2713 + printf_stderr("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), aItem->Frame(), aNewLayer); 1.2714 + } 1.2715 +#endif 1.2716 + } else { 1.2717 + // Let the display item check for geometry changes and decide what needs to be 1.2718 + // repainted. 1.2719 + 1.2720 + // We have an optimization to cache the drawing background-attachment: fixed canvas 1.2721 + // background images so we can scroll and just blit them when they are flattened into 1.2722 + // the same layer as scrolling content. NotifyRenderingChanged is only used to tell 1.2723 + // the canvas bg image item to purge this cache. We want to be careful not to accidentally 1.2724 + // purge the cache if we are just invalidating due to scrolling (ie the background image 1.2725 + // moves on the scrolling layer but it's rendering stays the same) so if 1.2726 + // AddOffsetAndComputeDifference is the only thing that will invalidate we skip the 1.2727 + // NotifyRenderingChanged call (ComputeInvalidationRegion for background images also calls 1.2728 + // NotifyRenderingChanged if anything changes). 1.2729 + if (oldGeometry->ComputeInvalidationRegion() == aGeometry->ComputeInvalidationRegion() && 1.2730 + *oldClip == aClip && invalid.IsEmpty() && changedFrames.Length() == 0) { 1.2731 + notifyRenderingChanged = false; 1.2732 + } 1.2733 + 1.2734 + oldGeometry->MoveBy(shift); 1.2735 + aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined); 1.2736 + oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(), 1.2737 + aClip, aGeometry->ComputeInvalidationRegion(), 1.2738 + &combined); 1.2739 + 1.2740 + // Add in any rect that the frame specified 1.2741 + combined.Or(combined, invalid); 1.2742 + 1.2743 + for (uint32_t i = 0; i < changedFrames.Length(); i++) { 1.2744 + combined.Or(combined, changedFrames[i]->GetVisualOverflowRect()); 1.2745 + } 1.2746 + 1.2747 + // Restrict invalidation to the clipped region 1.2748 + nsRegion clip; 1.2749 + if (aClip.ComputeRegionInClips(oldClip, shift, &clip)) { 1.2750 + combined.And(combined, clip); 1.2751 + } 1.2752 +#ifdef MOZ_DUMP_PAINTING 1.2753 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.2754 + if (!combined.IsEmpty()) { 1.2755 + printf_stderr("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), aItem->Frame(), aNewLayer); 1.2756 + } 1.2757 + } 1.2758 +#endif 1.2759 + } 1.2760 + if (!combined.IsEmpty()) { 1.2761 + if (notifyRenderingChanged) { 1.2762 + aItem->NotifyRenderingChanged(); 1.2763 + } 1.2764 + InvalidatePostTransformRegion(newThebesLayer, 1.2765 + combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), 1.2766 + GetTranslationForThebesLayer(newThebesLayer)); 1.2767 + } 1.2768 +} 1.2769 + 1.2770 +void 1.2771 +FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData, 1.2772 + nsDisplayItem* aItem, 1.2773 + const DisplayItemClip& aClip, 1.2774 + nsIFrame* aContainerLayerFrame, 1.2775 + LayerState aLayerState, 1.2776 + const nsPoint& aTopLeft, 1.2777 + nsAutoPtr<nsDisplayItemGeometry> aGeometry) 1.2778 +{ 1.2779 + ThebesLayer* layer = aLayerData->mLayer; 1.2780 + ThebesDisplayItemLayerUserData* thebesData = 1.2781 + static_cast<ThebesDisplayItemLayerUserData*> 1.2782 + (layer->GetUserData(&gThebesDisplayItemLayerUserData)); 1.2783 + nsRefPtr<BasicLayerManager> tempManager; 1.2784 + nsIntRect intClip; 1.2785 + bool hasClip = false; 1.2786 + if (aLayerState != LAYER_NONE) { 1.2787 + DisplayItemData *data = GetDisplayItemDataForManager(aItem, layer->Manager()); 1.2788 + if (data) { 1.2789 + tempManager = data->mInactiveManager; 1.2790 + } 1.2791 + if (!tempManager) { 1.2792 + tempManager = new BasicLayerManager(); 1.2793 + } 1.2794 + 1.2795 + // We need to grab these before calling AddLayerDisplayItem because it will overwrite them. 1.2796 + nsRegion clip; 1.2797 + DisplayItemClip* oldClip = nullptr; 1.2798 + GetOldLayerFor(aItem, nullptr, &oldClip); 1.2799 + hasClip = aClip.ComputeRegionInClips(oldClip, 1.2800 + aTopLeft - thebesData->mLastAnimatedGeometryRootOrigin, 1.2801 + &clip); 1.2802 + 1.2803 + if (hasClip) { 1.2804 + intClip = clip.GetBounds().ScaleToOutsidePixels(thebesData->mXScale, 1.2805 + thebesData->mYScale, 1.2806 + thebesData->mAppUnitsPerDevPixel); 1.2807 + } 1.2808 + } 1.2809 + 1.2810 + AddLayerDisplayItem(layer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry); 1.2811 + 1.2812 + ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(layer); 1.2813 + if (entry) { 1.2814 + entry->mContainerLayerFrame = aContainerLayerFrame; 1.2815 + if (entry->mContainerLayerGeneration == 0) { 1.2816 + entry->mContainerLayerGeneration = mContainerLayerGeneration; 1.2817 + } 1.2818 + if (tempManager) { 1.2819 + FrameLayerBuilder* layerBuilder = new FrameLayerBuilder(); 1.2820 + layerBuilder->Init(mDisplayListBuilder, tempManager, aLayerData); 1.2821 + 1.2822 + tempManager->BeginTransaction(); 1.2823 + if (mRetainingManager) { 1.2824 + layerBuilder->DidBeginRetainedLayerTransaction(tempManager); 1.2825 + } 1.2826 + 1.2827 + nsAutoPtr<LayerProperties> props(LayerProperties::CloneFrom(tempManager->GetRoot())); 1.2828 + nsRefPtr<Layer> tmpLayer = 1.2829 + aItem->BuildLayer(mDisplayListBuilder, tempManager, ContainerLayerParameters()); 1.2830 + // We have no easy way of detecting if this transaction will ever actually get finished. 1.2831 + // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp 1.2832 + if (!tmpLayer) { 1.2833 + tempManager->EndTransaction(nullptr, nullptr); 1.2834 + tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr); 1.2835 + return; 1.2836 + } 1.2837 + 1.2838 + // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been 1.2839 + // stored in layerBuilder. Manually add it now. 1.2840 + if (mRetainingManager) { 1.2841 +#ifdef DEBUG_DISPLAY_ITEM_DATA 1.2842 + LayerManagerData* parentLmd = static_cast<LayerManagerData*> 1.2843 + (layer->Manager()->GetUserData(&gLayerManagerUserData)); 1.2844 + LayerManagerData* lmd = static_cast<LayerManagerData*> 1.2845 + (tempManager->GetUserData(&gLayerManagerUserData)); 1.2846 + lmd->mParent = parentLmd; 1.2847 +#endif 1.2848 + layerBuilder->StoreDataForFrame(aItem, tmpLayer, LAYER_ACTIVE); 1.2849 + } 1.2850 + 1.2851 + tempManager->SetRoot(tmpLayer); 1.2852 + layerBuilder->WillEndTransaction(); 1.2853 + tempManager->AbortTransaction(); 1.2854 + 1.2855 + nsIntPoint offset = GetLastPaintOffset(layer) - GetTranslationForThebesLayer(layer); 1.2856 + props->MoveBy(-offset); 1.2857 + nsIntRegion invalid = props->ComputeDifferences(tmpLayer, nullptr); 1.2858 + if (aLayerState == LAYER_SVG_EFFECTS) { 1.2859 + invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(aItem->Frame(), 1.2860 + aItem->ToReferenceFrame(), 1.2861 + invalid); 1.2862 + } 1.2863 + if (!invalid.IsEmpty()) { 1.2864 +#ifdef MOZ_DUMP_PAINTING 1.2865 + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { 1.2866 + printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->Frame(), layer); 1.2867 + } 1.2868 +#endif 1.2869 + if (hasClip) { 1.2870 + invalid.And(invalid, intClip); 1.2871 + } 1.2872 + 1.2873 + invalid.ScaleRoundOut(thebesData->mXScale, thebesData->mYScale); 1.2874 + InvalidatePostTransformRegion(layer, invalid, 1.2875 + GetTranslationForThebesLayer(layer)); 1.2876 + } 1.2877 + } 1.2878 + ClippedDisplayItem* cdi = 1.2879 + entry->mItems.AppendElement(ClippedDisplayItem(aItem, 1.2880 + mContainerLayerGeneration)); 1.2881 + cdi->mInactiveLayerManager = tempManager; 1.2882 + } 1.2883 +} 1.2884 + 1.2885 +FrameLayerBuilder::DisplayItemData* 1.2886 +FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer, LayerState aState) 1.2887 +{ 1.2888 + DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager); 1.2889 + if (oldData) { 1.2890 + if (!oldData->mUsed) { 1.2891 + oldData->UpdateContents(aLayer, aState, mContainerLayerGeneration, aItem); 1.2892 + } 1.2893 + return oldData; 1.2894 + } 1.2895 + 1.2896 + LayerManagerData* lmd = static_cast<LayerManagerData*> 1.2897 + (mRetainingManager->GetUserData(&gLayerManagerUserData)); 1.2898 + 1.2899 + nsRefPtr<DisplayItemData> data = 1.2900 + new DisplayItemData(lmd, aItem->GetPerFrameKey(), 1.2901 + aLayer, aState, mContainerLayerGeneration); 1.2902 + 1.2903 + data->AddFrame(aItem->Frame()); 1.2904 + 1.2905 + nsAutoTArray<nsIFrame*,4> mergedFrames; 1.2906 + aItem->GetMergedFrames(&mergedFrames); 1.2907 + 1.2908 + for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { 1.2909 + data->AddFrame(mergedFrames[i]); 1.2910 + } 1.2911 + 1.2912 + lmd->mDisplayItems.PutEntry(data); 1.2913 + return data; 1.2914 +} 1.2915 + 1.2916 +void 1.2917 +FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame, 1.2918 + uint32_t aDisplayItemKey, 1.2919 + Layer* aLayer, 1.2920 + LayerState aState) 1.2921 +{ 1.2922 + DisplayItemData* oldData = GetDisplayItemData(aFrame, aDisplayItemKey); 1.2923 + if (oldData && oldData->mFrameList.Length() == 1) { 1.2924 + oldData->UpdateContents(aLayer, aState, mContainerLayerGeneration); 1.2925 + return; 1.2926 + } 1.2927 + 1.2928 + LayerManagerData* lmd = static_cast<LayerManagerData*> 1.2929 + (mRetainingManager->GetUserData(&gLayerManagerUserData)); 1.2930 + 1.2931 + nsRefPtr<DisplayItemData> data = 1.2932 + new DisplayItemData(lmd, aDisplayItemKey, aLayer, 1.2933 + aState, mContainerLayerGeneration); 1.2934 + 1.2935 + data->AddFrame(aFrame); 1.2936 + 1.2937 + lmd->mDisplayItems.PutEntry(data); 1.2938 +} 1.2939 + 1.2940 +FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem() 1.2941 +{ 1.2942 + if (mInactiveLayerManager) { 1.2943 + BasicLayerManager* basic = static_cast<BasicLayerManager*>(mInactiveLayerManager.get()); 1.2944 + basic->SetUserData(&gLayerManagerLayerBuilder, nullptr); 1.2945 + } 1.2946 +} 1.2947 + 1.2948 +void 1.2949 +FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer, 1.2950 + nsDisplayItem* aItem, 1.2951 + const DisplayItemClip& aClip, 1.2952 + LayerState aLayerState, 1.2953 + const nsPoint& aTopLeft, 1.2954 + BasicLayerManager* aManager, 1.2955 + nsAutoPtr<nsDisplayItemGeometry> aGeometry) 1.2956 +{ 1.2957 + if (aLayer->Manager() != mRetainingManager) 1.2958 + return; 1.2959 + 1.2960 + DisplayItemData *data = StoreDataForFrame(aItem, aLayer, aLayerState); 1.2961 + ThebesLayer *t = aLayer->AsThebesLayer(); 1.2962 + if (t) { 1.2963 + data->mGeometry = aGeometry; 1.2964 + data->mClip = aClip; 1.2965 + } 1.2966 + data->mInactiveManager = aManager; 1.2967 +} 1.2968 + 1.2969 +nsIntPoint 1.2970 +FrameLayerBuilder::GetLastPaintOffset(ThebesLayer* aLayer) 1.2971 +{ 1.2972 + ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer); 1.2973 + if (entry) { 1.2974 + if (entry->mContainerLayerGeneration == 0) { 1.2975 + entry->mContainerLayerGeneration = mContainerLayerGeneration; 1.2976 + } 1.2977 + if (entry->mHasExplicitLastPaintOffset) 1.2978 + return entry->mLastPaintOffset; 1.2979 + } 1.2980 + return GetTranslationForThebesLayer(aLayer); 1.2981 +} 1.2982 + 1.2983 +void 1.2984 +FrameLayerBuilder::SaveLastPaintOffset(ThebesLayer* aLayer) 1.2985 +{ 1.2986 + ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer); 1.2987 + if (entry) { 1.2988 + if (entry->mContainerLayerGeneration == 0) { 1.2989 + entry->mContainerLayerGeneration = mContainerLayerGeneration; 1.2990 + } 1.2991 + entry->mLastPaintOffset = GetTranslationForThebesLayer(aLayer); 1.2992 + entry->mHasExplicitLastPaintOffset = true; 1.2993 + } 1.2994 +} 1.2995 + 1.2996 +bool 1.2997 +FrameLayerBuilder::CheckInLayerTreeCompressionMode() 1.2998 +{ 1.2999 + if (mInLayerTreeCompressionMode) { 1.3000 + return true; 1.3001 + } 1.3002 + 1.3003 + // If we wanted to be in layer tree compression mode, but weren't, then scheduled 1.3004 + // a delayed repaint where we will be. 1.3005 + mRootPresContext->PresShell()->GetRootFrame()->SchedulePaint(nsIFrame::PAINT_DELAYED_COMPRESS); 1.3006 + 1.3007 + return false; 1.3008 +} 1.3009 + 1.3010 +void 1.3011 +ContainerState::CollectOldLayers() 1.3012 +{ 1.3013 + for (Layer* layer = mContainerLayer->GetFirstChild(); layer; 1.3014 + layer = layer->GetNextSibling()) { 1.3015 + NS_ASSERTION(!layer->HasUserData(&gMaskLayerUserData), 1.3016 + "Mask layer in layer tree; could not be recycled."); 1.3017 + if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) { 1.3018 + NS_ASSERTION(layer->AsThebesLayer(), "Wrong layer type"); 1.3019 + mRecycledThebesLayers.AppendElement(static_cast<ThebesLayer*>(layer)); 1.3020 + } 1.3021 + 1.3022 + if (Layer* maskLayer = layer->GetMaskLayer()) { 1.3023 + NS_ASSERTION(maskLayer->GetType() == Layer::TYPE_IMAGE, 1.3024 + "Could not recycle mask layer, unsupported layer type."); 1.3025 + mRecycledMaskImageLayers.Put(layer, static_cast<ImageLayer*>(maskLayer)); 1.3026 + } 1.3027 + } 1.3028 +} 1.3029 + 1.3030 +void 1.3031 +ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData) 1.3032 +{ 1.3033 + while (!mThebesLayerDataStack.IsEmpty()) { 1.3034 + PopThebesLayerData(); 1.3035 + } 1.3036 + 1.3037 + uint32_t textContentFlags = 0; 1.3038 + 1.3039 + // Make sure that current/existing layers are added to the parent and are 1.3040 + // in the correct order. 1.3041 + Layer* layer = nullptr; 1.3042 + for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i) { 1.3043 + Layer* prevChild = i == 0 ? nullptr : mNewChildLayers[i - 1].get(); 1.3044 + layer = mNewChildLayers[i]; 1.3045 + 1.3046 + if (!layer->GetVisibleRegion().IsEmpty()) { 1.3047 + textContentFlags |= layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA; 1.3048 + } 1.3049 + 1.3050 + if (!layer->GetParent()) { 1.3051 + // This is not currently a child of the container, so just add it 1.3052 + // now. 1.3053 + mContainerLayer->InsertAfter(layer, prevChild); 1.3054 + continue; 1.3055 + } 1.3056 + 1.3057 + NS_ASSERTION(layer->GetParent() == mContainerLayer, 1.3058 + "Layer shouldn't be the child of some other container"); 1.3059 + if (layer->GetPrevSibling() != prevChild) { 1.3060 + mContainerLayer->RepositionChild(layer, prevChild); 1.3061 + } 1.3062 + } 1.3063 + 1.3064 + // Remove old layers that have become unused. 1.3065 + if (!layer) { 1.3066 + layer = mContainerLayer->GetFirstChild(); 1.3067 + } else { 1.3068 + layer = layer->GetNextSibling(); 1.3069 + } 1.3070 + while (layer) { 1.3071 + Layer *layerToRemove = layer; 1.3072 + layer = layer->GetNextSibling(); 1.3073 + mContainerLayer->RemoveChild(layerToRemove); 1.3074 + } 1.3075 + 1.3076 + *aTextContentFlags = textContentFlags; 1.3077 +} 1.3078 + 1.3079 +static inline gfxSize RoundToFloatPrecision(const gfxSize& aSize) 1.3080 +{ 1.3081 + return gfxSize(float(aSize.width), float(aSize.height)); 1.3082 +} 1.3083 + 1.3084 +static bool 1.3085 +ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder, 1.3086 + nsDisplayListBuilder* aDisplayListBuilder, 1.3087 + nsIFrame* aContainerFrame, 1.3088 + const gfx3DMatrix* aTransform, 1.3089 + const ContainerLayerParameters& aIncomingScale, 1.3090 + ContainerLayer* aLayer, 1.3091 + LayerState aState, 1.3092 + ContainerLayerParameters& aOutgoingScale) 1.3093 +{ 1.3094 + nsIntPoint offset; 1.3095 + 1.3096 + gfx3DMatrix transform = 1.3097 + gfx3DMatrix::ScalingMatrix(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0); 1.3098 + if (aTransform) { 1.3099 + // aTransform is applied first, then the scale is applied to the result 1.3100 + transform = (*aTransform)*transform; 1.3101 + // Set any matrix entries close to integers to be those exact integers. 1.3102 + // This protects against floating-point inaccuracies causing problems 1.3103 + // in the checks below. 1.3104 + transform.NudgeToIntegers(); 1.3105 + } 1.3106 + gfxMatrix transform2d; 1.3107 + if (aContainerFrame && 1.3108 + (aState == LAYER_INACTIVE || aState == LAYER_SVG_EFFECTS) && 1.3109 + (!aTransform || (aTransform->Is2D(&transform2d) && 1.3110 + !transform2d.HasNonTranslation()))) { 1.3111 + // When we have an inactive ContainerLayer, translate the container by the offset to the 1.3112 + // reference frame (and offset all child layers by the reverse) so that the coordinate 1.3113 + // space of the child layers isn't affected by scrolling. 1.3114 + // This gets confusing for complicated transform (since we'd have to compute the scale 1.3115 + // factors for the matrix), so we don't bother. Any frames that are building an nsDisplayTransform 1.3116 + // for a css transform would have 0,0 as their offset to the reference frame, so this doesn't 1.3117 + // matter. 1.3118 + nsPoint appUnitOffset = aDisplayListBuilder->ToReferenceFrame(aContainerFrame); 1.3119 + nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel(); 1.3120 + offset = nsIntPoint( 1.3121 + NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.x, appUnitsPerDevPixel)*aIncomingScale.mXScale), 1.3122 + NS_lround(NSAppUnitsToDoublePixels(appUnitOffset.y, appUnitsPerDevPixel)*aIncomingScale.mYScale)); 1.3123 + } 1.3124 + transform = transform * gfx3DMatrix::Translation(offset.x + aIncomingScale.mOffset.x, offset.y + aIncomingScale.mOffset.y, 0); 1.3125 + 1.3126 + if (transform.IsSingular()) { 1.3127 + return false; 1.3128 + } 1.3129 + 1.3130 + bool canDraw2D = transform.CanDraw2D(&transform2d); 1.3131 + gfxSize scale; 1.3132 + // XXX Should we do something for 3D transforms? 1.3133 + if (canDraw2D) { 1.3134 + // If the container's transform is animated off main thread, fix a suitable scale size 1.3135 + // for animation 1.3136 + if (aContainerFrame->GetContent() && 1.3137 + nsLayoutUtils::HasAnimationsForCompositor( 1.3138 + aContainerFrame->GetContent(), eCSSProperty_transform)) { 1.3139 + scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(aContainerFrame->GetContent()); 1.3140 + } else { 1.3141 + // Scale factors are normalized to a power of 2 to reduce the number of resolution changes 1.3142 + scale = RoundToFloatPrecision(transform2d.ScaleFactors(true)); 1.3143 + // For frames with a changing transform that's not just a translation, 1.3144 + // round scale factors up to nearest power-of-2 boundary so that we don't 1.3145 + // keep having to redraw the content as it scales up and down. Rounding up to nearest 1.3146 + // power-of-2 boundary ensures we never scale up, only down --- avoiding 1.3147 + // jaggies. It also ensures we never scale down by more than a factor of 2, 1.3148 + // avoiding bad downscaling quality. 1.3149 + gfxMatrix frameTransform; 1.3150 + if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform) && 1.3151 + aTransform && 1.3152 + (!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) { 1.3153 + // Don't clamp the scale factor when the new desired scale factor matches the old one 1.3154 + // or it was previously unscaled. 1.3155 + bool clamp = true; 1.3156 + Matrix oldFrameTransform2d; 1.3157 + if (aLayer->GetBaseTransform().Is2D(&oldFrameTransform2d)) { 1.3158 + gfxSize oldScale = RoundToFloatPrecision(ThebesMatrix(oldFrameTransform2d).ScaleFactors(true)); 1.3159 + if (oldScale == scale || oldScale == gfxSize(1.0, 1.0)) { 1.3160 + clamp = false; 1.3161 + } 1.3162 + } 1.3163 + if (clamp) { 1.3164 + scale.width = gfxUtils::ClampToScaleFactor(scale.width); 1.3165 + scale.height = gfxUtils::ClampToScaleFactor(scale.height); 1.3166 + } 1.3167 + } else { 1.3168 + // XXX Do we need to move nearly-integer values to integers here? 1.3169 + } 1.3170 + } 1.3171 + // If the scale factors are too small, just use 1.0. The content is being 1.3172 + // scaled out of sight anyway. 1.3173 + if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) { 1.3174 + scale = gfxSize(1.0, 1.0); 1.3175 + } 1.3176 + } else { 1.3177 + scale = gfxSize(1.0, 1.0); 1.3178 + } 1.3179 + 1.3180 + // Store the inverse of our resolution-scale on the layer 1.3181 + Matrix4x4 baseTransform; 1.3182 + ToMatrix4x4(transform, baseTransform); 1.3183 + aLayer->SetBaseTransform(baseTransform); 1.3184 + aLayer->SetPreScale(1.0f/float(scale.width), 1.3185 + 1.0f/float(scale.height)); 1.3186 + aLayer->SetInheritedScale(aIncomingScale.mXScale, 1.3187 + aIncomingScale.mYScale); 1.3188 + 1.3189 + aOutgoingScale = 1.3190 + ContainerLayerParameters(scale.width, scale.height, -offset, aIncomingScale); 1.3191 + if (aTransform) { 1.3192 + aOutgoingScale.mInTransformedSubtree = true; 1.3193 + if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform)) { 1.3194 + aOutgoingScale.mInActiveTransformedSubtree = true; 1.3195 + } 1.3196 + } 1.3197 + bool isRetained = aLayer->Manager()->IsWidgetLayerManager(); 1.3198 + if (isRetained && (!canDraw2D || transform2d.HasNonIntegerTranslation())) { 1.3199 + aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true; 1.3200 + } 1.3201 + return true; 1.3202 +} 1.3203 + 1.3204 +/* static */ PLDHashOperator 1.3205 +FrameLayerBuilder::RestoreDisplayItemData(nsRefPtrHashKey<DisplayItemData>* aEntry, void* aUserArg) 1.3206 +{ 1.3207 + DisplayItemData* data = aEntry->GetKey(); 1.3208 + uint32_t *generation = static_cast<uint32_t*>(aUserArg); 1.3209 + 1.3210 + if (data->mUsed && data->mContainerLayerGeneration >= *generation) { 1.3211 + return PL_DHASH_REMOVE; 1.3212 + } 1.3213 + 1.3214 + return PL_DHASH_NEXT; 1.3215 +} 1.3216 + 1.3217 +/* static */ PLDHashOperator 1.3218 +FrameLayerBuilder::RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry, void* aUserArg) 1.3219 +{ 1.3220 + uint32_t *generation = static_cast<uint32_t*>(aUserArg); 1.3221 + 1.3222 + if (aEntry->mContainerLayerGeneration >= *generation) { 1.3223 + // We can just remove these items rather than attempting to revert them 1.3224 + // because we're going to want to invalidate everything when transitioning 1.3225 + // to component alpha flattening. 1.3226 + return PL_DHASH_REMOVE; 1.3227 + } 1.3228 + 1.3229 + for (uint32_t i = 0; i < aEntry->mItems.Length(); i++) { 1.3230 + if (aEntry->mItems[i].mContainerLayerGeneration >= *generation) { 1.3231 + aEntry->mItems.TruncateLength(i); 1.3232 + return PL_DHASH_NEXT; 1.3233 + } 1.3234 + } 1.3235 + 1.3236 + return PL_DHASH_NEXT; 1.3237 +} 1.3238 + 1.3239 +already_AddRefed<ContainerLayer> 1.3240 +FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, 1.3241 + LayerManager* aManager, 1.3242 + nsIFrame* aContainerFrame, 1.3243 + nsDisplayItem* aContainerItem, 1.3244 + const nsDisplayList& aChildren, 1.3245 + const ContainerLayerParameters& aParameters, 1.3246 + const gfx3DMatrix* aTransform, 1.3247 + uint32_t aFlags) 1.3248 +{ 1.3249 + uint32_t containerDisplayItemKey = 1.3250 + aContainerItem ? aContainerItem->GetPerFrameKey() : nsDisplayItem::TYPE_ZERO; 1.3251 + NS_ASSERTION(aContainerFrame, "Container display items here should have a frame"); 1.3252 + NS_ASSERTION(!aContainerItem || 1.3253 + aContainerItem->Frame() == aContainerFrame, 1.3254 + "Container display item must match given frame"); 1.3255 + 1.3256 + if (!aParameters.mXScale || !aParameters.mYScale) { 1.3257 + return nullptr; 1.3258 + } 1.3259 + 1.3260 + nsRefPtr<ContainerLayer> containerLayer; 1.3261 + if (aManager == mRetainingManager) { 1.3262 + // Using GetOldLayerFor will search merged frames, as well as the underlying 1.3263 + // frame. The underlying frame can change when a page scrolls, so this 1.3264 + // avoids layer recreation in the situation that a new underlying frame is 1.3265 + // picked for a layer. 1.3266 + Layer* oldLayer = nullptr; 1.3267 + if (aContainerItem) { 1.3268 + oldLayer = GetOldLayerFor(aContainerItem); 1.3269 + } else { 1.3270 + DisplayItemData *data = GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey); 1.3271 + if (data) { 1.3272 + oldLayer = data->mLayer; 1.3273 + } 1.3274 + } 1.3275 + 1.3276 + if (oldLayer) { 1.3277 + NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager"); 1.3278 + if (oldLayer->HasUserData(&gThebesDisplayItemLayerUserData)) { 1.3279 + // The old layer for this item is actually our ThebesLayer 1.3280 + // because we rendered its layer into that ThebesLayer. So we 1.3281 + // don't actually have a retained container layer. 1.3282 + } else { 1.3283 + NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER, 1.3284 + "Wrong layer type"); 1.3285 + containerLayer = static_cast<ContainerLayer*>(oldLayer); 1.3286 + containerLayer->SetMaskLayer(nullptr); 1.3287 + } 1.3288 + } 1.3289 + } 1.3290 + if (!containerLayer) { 1.3291 + // No suitable existing layer was found. 1.3292 + containerLayer = aManager->CreateContainerLayer(); 1.3293 + if (!containerLayer) 1.3294 + return nullptr; 1.3295 + } 1.3296 + 1.3297 + LayerState state = aContainerItem ? aContainerItem->GetLayerState(aBuilder, aManager, aParameters) : LAYER_ACTIVE; 1.3298 + if (state == LAYER_INACTIVE && 1.3299 + nsDisplayItem::ForceActiveLayers()) { 1.3300 + state = LAYER_ACTIVE; 1.3301 + } 1.3302 + 1.3303 + if (aContainerItem && state == LAYER_ACTIVE_EMPTY) { 1.3304 + // Empty layers only have metadata and should never have display items. We 1.3305 + // early exit because later, invalidation will walk up the frame tree to 1.3306 + // determine which thebes layer gets invalidated. Since an empty layer 1.3307 + // should never have anything to paint, it should never be invalidated. 1.3308 + NS_ASSERTION(aChildren.IsEmpty(), "Should have no children"); 1.3309 + return containerLayer.forget(); 1.3310 + } 1.3311 + 1.3312 + ContainerLayerParameters scaleParameters; 1.3313 + if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aTransform, aParameters, 1.3314 + containerLayer, state, scaleParameters)) { 1.3315 + return nullptr; 1.3316 + } 1.3317 + 1.3318 + uint32_t oldGeneration = mContainerLayerGeneration; 1.3319 + mContainerLayerGeneration = ++mMaxContainerLayerGeneration; 1.3320 + 1.3321 + nsRefPtr<RefCountedRegion> thebesLayerInvalidRegion = nullptr; 1.3322 + if (mRetainingManager) { 1.3323 + if (aContainerItem) { 1.3324 + StoreDataForFrame(aContainerItem, containerLayer, LAYER_ACTIVE); 1.3325 + } else { 1.3326 + StoreDataForFrame(aContainerFrame, containerDisplayItemKey, containerLayer, LAYER_ACTIVE); 1.3327 + } 1.3328 + } 1.3329 + 1.3330 + LayerManagerData* data = static_cast<LayerManagerData*> 1.3331 + (aManager->GetUserData(&gLayerManagerUserData)); 1.3332 + 1.3333 + nsRect bounds; 1.3334 + nsIntRect pixBounds; 1.3335 + int32_t appUnitsPerDevPixel; 1.3336 + uint32_t stateFlags = 0; 1.3337 + if ((aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) && 1.3338 + mRetainingManager && !mRetainingManager->AreComponentAlphaLayersEnabled()) { 1.3339 + stateFlags = ContainerState::NO_COMPONENT_ALPHA; 1.3340 + } 1.3341 + uint32_t flags; 1.3342 + while (true) { 1.3343 + ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(), 1.3344 + aContainerFrame, aContainerItem, 1.3345 + containerLayer, scaleParameters); 1.3346 + 1.3347 + state.ProcessDisplayItems(aChildren, stateFlags); 1.3348 + 1.3349 + // Set CONTENT_COMPONENT_ALPHA if any of our children have it. 1.3350 + // This is suboptimal ... a child could have text that's over transparent 1.3351 + // pixels in its own layer, but over opaque parts of previous siblings. 1.3352 + state.Finish(&flags, data); 1.3353 + bounds = state.GetChildrenBounds(); 1.3354 + pixBounds = state.ScaleToOutsidePixels(bounds, false); 1.3355 + appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel(); 1.3356 + 1.3357 + if ((flags & Layer::CONTENT_COMPONENT_ALPHA) && 1.3358 + mRetainingManager && 1.3359 + !mRetainingManager->AreComponentAlphaLayersEnabled() && 1.3360 + !stateFlags) { 1.3361 + // Since we don't want any component alpha layers on BasicLayers, we repeat 1.3362 + // the layer building process with this explicitely forced off. 1.3363 + // We restore the previous FrameLayerBuilder state since the first set 1.3364 + // of layer building will have changed it. 1.3365 + stateFlags = ContainerState::NO_COMPONENT_ALPHA; 1.3366 + data->mDisplayItems.EnumerateEntries(RestoreDisplayItemData, 1.3367 + &mContainerLayerGeneration); 1.3368 + mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries, 1.3369 + &mContainerLayerGeneration); 1.3370 + aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA); 1.3371 + continue; 1.3372 + } 1.3373 + break; 1.3374 + } 1.3375 + 1.3376 + NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds"); 1.3377 + pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y)); 1.3378 + if (aParameters.mAncestorClipRect && !(aFlags & CONTAINER_NOT_CLIPPED_BY_ANCESTORS)) { 1.3379 + SetVisibleRegionForLayer(containerLayer, nsIntRegion(pixBounds), 1.3380 + *aParameters.mAncestorClipRect); 1.3381 + } else { 1.3382 + containerLayer->SetVisibleRegion(pixBounds); 1.3383 + } 1.3384 + // Make sure that rounding the visible region out didn't add any area 1.3385 + // we won't paint 1.3386 + if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) { 1.3387 + bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale); 1.3388 + if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) { 1.3389 + // Clear CONTENT_COMPONENT_ALPHA 1.3390 + flags = Layer::CONTENT_OPAQUE; 1.3391 + } 1.3392 + } 1.3393 + containerLayer->SetContentFlags(flags); 1.3394 + 1.3395 + mContainerLayerGeneration = oldGeneration; 1.3396 + nsPresContext::ClearNotifySubDocInvalidationData(containerLayer); 1.3397 + 1.3398 + return containerLayer.forget(); 1.3399 +} 1.3400 + 1.3401 +Layer* 1.3402 +FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder, 1.3403 + nsDisplayItem* aItem) 1.3404 +{ 1.3405 + Layer* layer = GetOldLayerFor(aItem); 1.3406 + if (!layer) 1.3407 + return nullptr; 1.3408 + if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) { 1.3409 + // This layer was created to render Thebes-rendered content for this 1.3410 + // display item. The display item should not use it for its own 1.3411 + // layer rendering. 1.3412 + return nullptr; 1.3413 + } 1.3414 + layer->SetMaskLayer(nullptr); 1.3415 + return layer; 1.3416 +} 1.3417 + 1.3418 +/* static */ void 1.3419 +FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager) 1.3420 +{ 1.3421 + LayerManagerData* data = static_cast<LayerManagerData*> 1.3422 + (aManager->GetUserData(&gLayerManagerUserData)); 1.3423 + if (data) { 1.3424 + data->mInvalidateAllLayers = true; 1.3425 + } 1.3426 +} 1.3427 + 1.3428 +/* static */ void 1.3429 +FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame) 1.3430 +{ 1.3431 + nsTArray<DisplayItemData*> *array = 1.3432 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty())); 1.3433 + if (array) { 1.3434 + for (uint32_t i = 0; i < array->Length(); i++) { 1.3435 + array->ElementAt(i)->mParent->mInvalidateAllLayers = true; 1.3436 + } 1.3437 + } 1.3438 +} 1.3439 + 1.3440 +/* static */ 1.3441 +Layer* 1.3442 +FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey) 1.3443 +{ 1.3444 + //TODO: This isn't completely correct, since a frame could exist as a layer 1.3445 + // in the normal widget manager, and as a different layer (or no layer) 1.3446 + // in the secondary manager 1.3447 + 1.3448 + nsTArray<DisplayItemData*> *array = 1.3449 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty())); 1.3450 + if (array) { 1.3451 + for (uint32_t i = 0; i < array->Length(); i++) { 1.3452 + DisplayItemData *element = array->ElementAt(i); 1.3453 + if (!element->mParent->mLayerManager->IsWidgetLayerManager()) { 1.3454 + continue; 1.3455 + } 1.3456 + if (element->mDisplayItemKey == aDisplayItemKey) { 1.3457 + if (element->mOptLayer) { 1.3458 + return element->mOptLayer; 1.3459 + } 1.3460 + 1.3461 + Layer* layer = element->mLayer; 1.3462 + if (!layer->HasUserData(&gColorLayerUserData) && 1.3463 + !layer->HasUserData(&gImageLayerUserData) && 1.3464 + !layer->HasUserData(&gThebesDisplayItemLayerUserData)) { 1.3465 + return layer; 1.3466 + } 1.3467 + } 1.3468 + } 1.3469 + } 1.3470 + return nullptr; 1.3471 +} 1.3472 + 1.3473 +static gfxSize 1.3474 +PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale, 1.3475 + const gfxSize& aScale) 1.3476 +{ 1.3477 + gfx3DMatrix transform = 1.3478 + gfx3DMatrix::ScalingMatrix(aScale.width, aScale.height, 1.0); 1.3479 + if (aFrame != aAncestorWithScale) { 1.3480 + // aTransform is applied first, then the scale is applied to the result 1.3481 + transform = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestorWithScale)*transform; 1.3482 + } 1.3483 + gfxMatrix transform2d; 1.3484 + if (transform.CanDraw2D(&transform2d)) { 1.3485 + return transform2d.ScaleFactors(true); 1.3486 + } 1.3487 + return gfxSize(1.0, 1.0); 1.3488 +} 1.3489 + 1.3490 +gfxSize 1.3491 +FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame) 1.3492 +{ 1.3493 + nsIFrame* last; 1.3494 + for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) { 1.3495 + last = f; 1.3496 + 1.3497 + if (nsLayoutUtils::IsPopup(f)) { 1.3498 + // Don't examine ancestors of a popup. It won't make sense to check 1.3499 + // the transform from some content inside the popup to some content 1.3500 + // which is an ancestor of the popup. 1.3501 + break; 1.3502 + } 1.3503 + 1.3504 + nsTArray<DisplayItemData*> *array = 1.3505 + reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty())); 1.3506 + if (!array) { 1.3507 + continue; 1.3508 + } 1.3509 + 1.3510 + for (uint32_t i = 0; i < array->Length(); i++) { 1.3511 + Layer* layer = array->ElementAt(i)->mLayer; 1.3512 + ContainerLayer* container = layer->AsContainerLayer(); 1.3513 + if (!container || 1.3514 + !layer->Manager()->IsWidgetLayerManager()) { 1.3515 + continue; 1.3516 + } 1.3517 + for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) { 1.3518 + ThebesDisplayItemLayerUserData* data = 1.3519 + static_cast<ThebesDisplayItemLayerUserData*> 1.3520 + (l->GetUserData(&gThebesDisplayItemLayerUserData)); 1.3521 + if (data) { 1.3522 + return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale)); 1.3523 + } 1.3524 + } 1.3525 + } 1.3526 + } 1.3527 + 1.3528 + return PredictScaleForContent(aFrame, last, 1.3529 + last->PresContext()->PresShell()->GetResolution()); 1.3530 +} 1.3531 + 1.3532 +#ifdef MOZ_DUMP_PAINTING 1.3533 +static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder) 1.3534 +{ 1.3535 + bool snap; 1.3536 + nsRect appUnitBounds = aItem->GetBounds(aBuilder, &snap); 1.3537 + gfxRect bounds(appUnitBounds.x, appUnitBounds.y, appUnitBounds.width, appUnitBounds.height); 1.3538 + bounds.ScaleInverse(aDest->AppUnitsPerDevPixel()); 1.3539 + 1.3540 + nsRefPtr<gfxASurface> surf = 1.3541 + gfxPlatform::GetPlatform()->CreateOffscreenSurface(IntSize(bounds.width, bounds.height), 1.3542 + gfxContentType::COLOR_ALPHA); 1.3543 + surf->SetDeviceOffset(-bounds.TopLeft()); 1.3544 + nsRefPtr<gfxContext> context = new gfxContext(surf); 1.3545 + nsRefPtr<nsRenderingContext> ctx = new nsRenderingContext(); 1.3546 + ctx->Init(aDest->DeviceContext(), context); 1.3547 + 1.3548 + aItem->Paint(aBuilder, ctx); 1.3549 + DumpPaintedImage(aItem, surf); 1.3550 + aItem->SetPainted(); 1.3551 + 1.3552 + surf->SetDeviceOffset(gfxPoint(0, 0)); 1.3553 + aDest->ThebesContext()->SetSource(surf, bounds.TopLeft()); 1.3554 + aDest->ThebesContext()->Rectangle(bounds); 1.3555 + aDest->ThebesContext()->Fill(); 1.3556 +} 1.3557 +#endif 1.3558 + 1.3559 +/* static */ void 1.3560 +FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray<ClippedDisplayItem>& aItems, 1.3561 + nsDisplayListBuilder *aBuilder, 1.3562 + const nsIntRegion& aRegionToDraw, 1.3563 + const nsIntPoint& aOffset, 1.3564 + int32_t aAppUnitsPerDevPixel, 1.3565 + float aXScale, 1.3566 + float aYScale) 1.3567 +{ 1.3568 + uint32_t i; 1.3569 + // Update visible regions. We need perform visibility analysis again 1.3570 + // because we may be asked to draw into part of a ThebesLayer that 1.3571 + // isn't actually visible in the window (e.g., because a ThebesLayer 1.3572 + // expanded its visible region to a rectangle internally), in which 1.3573 + // case the mVisibleRect stored in the display item may be wrong. 1.3574 + nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel); 1.3575 + visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel), 1.3576 + NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel)); 1.3577 + visible.ScaleInverseRoundOut(aXScale, aYScale); 1.3578 + 1.3579 + for (i = aItems.Length(); i > 0; --i) { 1.3580 + ClippedDisplayItem* cdi = &aItems[i - 1]; 1.3581 + const DisplayItemClip& clip = cdi->mItem->GetClip(); 1.3582 + 1.3583 + NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel, 1.3584 + "a thebes layer should contain items only at the same zoom"); 1.3585 + 1.3586 + NS_ABORT_IF_FALSE(clip.HasClip() || 1.3587 + clip.GetRoundedRectCount() == 0, 1.3588 + "If we have rounded rects, we must have a clip rect"); 1.3589 + 1.3590 + if (!clip.IsRectAffectedByClip(visible.GetBounds())) { 1.3591 + cdi->mItem->RecomputeVisibility(aBuilder, &visible); 1.3592 + continue; 1.3593 + } 1.3594 + 1.3595 + // Do a little dance to account for the fact that we're clipping 1.3596 + // to cdi->mClipRect 1.3597 + nsRegion clipped; 1.3598 + clipped.And(visible, clip.NonRoundedIntersection()); 1.3599 + nsRegion finalClipped = clipped; 1.3600 + cdi->mItem->RecomputeVisibility(aBuilder, &finalClipped); 1.3601 + // If we have rounded clip rects, don't subtract from the visible 1.3602 + // region since we aren't displaying everything inside the rect. 1.3603 + if (clip.GetRoundedRectCount() == 0) { 1.3604 + nsRegion removed; 1.3605 + removed.Sub(clipped, finalClipped); 1.3606 + nsRegion newVisible; 1.3607 + newVisible.Sub(visible, removed); 1.3608 + // Don't let the visible region get too complex. 1.3609 + if (newVisible.GetNumRects() <= 15) { 1.3610 + visible = newVisible; 1.3611 + } 1.3612 + } 1.3613 + } 1.3614 +} 1.3615 + 1.3616 +void 1.3617 +FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems, 1.3618 + const nsIntRect& aRect, 1.3619 + gfxContext *aContext, 1.3620 + nsRenderingContext *aRC, 1.3621 + nsDisplayListBuilder* aBuilder, 1.3622 + nsPresContext* aPresContext, 1.3623 + const nsIntPoint& aOffset, 1.3624 + float aXScale, float aYScale, 1.3625 + int32_t aCommonClipCount) 1.3626 +{ 1.3627 + int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel(); 1.3628 + nsRect boundRect = aRect.ToAppUnits(appUnitsPerDevPixel); 1.3629 + boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel), 1.3630 + NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel)); 1.3631 + boundRect.ScaleInverseRoundOut(aXScale, aYScale); 1.3632 + 1.3633 + DisplayItemClip currentClip; 1.3634 + bool currentClipIsSetInContext = false; 1.3635 + DisplayItemClip tmpClip; 1.3636 + 1.3637 + for (uint32_t i = 0; i < aItems.Length(); ++i) { 1.3638 + ClippedDisplayItem* cdi = &aItems[i]; 1.3639 + 1.3640 + nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect); 1.3641 + if (paintRect.IsEmpty()) 1.3642 + continue; 1.3643 + 1.3644 + // If the new desired clip state is different from the current state, 1.3645 + // update the clip. 1.3646 + const DisplayItemClip* clip = &cdi->mItem->GetClip(); 1.3647 + if (clip->GetRoundedRectCount() > 0 && 1.3648 + !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) { 1.3649 + tmpClip = *clip; 1.3650 + tmpClip.RemoveRoundedCorners(); 1.3651 + clip = &tmpClip; 1.3652 + } 1.3653 + if (currentClipIsSetInContext != clip->HasClip() || 1.3654 + (clip->HasClip() && *clip != currentClip)) { 1.3655 + if (currentClipIsSetInContext) { 1.3656 + aContext->Restore(); 1.3657 + } 1.3658 + currentClipIsSetInContext = clip->HasClip(); 1.3659 + if (currentClipIsSetInContext) { 1.3660 + currentClip = *clip; 1.3661 + aContext->Save(); 1.3662 + NS_ASSERTION(aCommonClipCount < 100, 1.3663 + "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong."); 1.3664 + currentClip.ApplyTo(aContext, aPresContext, aCommonClipCount); 1.3665 + aContext->NewPath(); 1.3666 + } 1.3667 + } 1.3668 + 1.3669 + if (cdi->mInactiveLayerManager) { 1.3670 + PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aRC); 1.3671 + } else { 1.3672 + nsIFrame* frame = cdi->mItem->Frame(); 1.3673 + frame->AddStateBits(NS_FRAME_PAINTED_THEBES); 1.3674 +#ifdef MOZ_DUMP_PAINTING 1.3675 + 1.3676 + if (gfxUtils::sDumpPainting) { 1.3677 + DebugPaintItem(aRC, cdi->mItem, aBuilder); 1.3678 + } else { 1.3679 +#else 1.3680 + { 1.3681 +#endif 1.3682 + cdi->mItem->Paint(aBuilder, aRC); 1.3683 + } 1.3684 + } 1.3685 + 1.3686 + if (CheckDOMModified()) 1.3687 + break; 1.3688 + } 1.3689 + 1.3690 + if (currentClipIsSetInContext) { 1.3691 + aContext->Restore(); 1.3692 + } 1.3693 +} 1.3694 + 1.3695 +/** 1.3696 + * Returns true if it is preferred to draw the list of display 1.3697 + * items separately for each rect in the visible region rather 1.3698 + * than clipping to a complex region. 1.3699 + */ 1.3700 +static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip) 1.3701 +{ 1.3702 + if (!gfxPrefs::LayoutPaintRectsSeparately() || 1.3703 + aContext->IsCairo() || 1.3704 + aClip == DrawRegionClip::CLIP_NONE) { 1.3705 + return false; 1.3706 + } 1.3707 + 1.3708 + DrawTarget *dt = aContext->GetDrawTarget(); 1.3709 + return dt->GetType() == BackendType::DIRECT2D; 1.3710 +} 1.3711 + 1.3712 +static void DrawForcedBackgroundColor(gfxContext* aContext, Layer* aLayer, nscolor aBackgroundColor) 1.3713 +{ 1.3714 + if (NS_GET_A(aBackgroundColor) > 0) { 1.3715 + nsIntRect r = aLayer->GetVisibleRegion().GetBounds(); 1.3716 + aContext->NewPath(); 1.3717 + aContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height)); 1.3718 + aContext->SetColor(gfxRGBA(aBackgroundColor)); 1.3719 + aContext->Fill(); 1.3720 + } 1.3721 +} 1.3722 + 1.3723 +/* 1.3724 + * A note on residual transforms: 1.3725 + * 1.3726 + * In a transformed subtree we sometimes apply the ThebesLayer's 1.3727 + * "residual transform" when drawing content into the ThebesLayer. 1.3728 + * This is a translation by components in the range [-0.5,0.5) provided 1.3729 + * by the layer system; applying the residual transform followed by the 1.3730 + * transforms used by layer compositing ensures that the subpixel alignment 1.3731 + * of the content of the ThebesLayer exactly matches what it would be if 1.3732 + * we used cairo/Thebes to draw directly to the screen without going through 1.3733 + * retained layer buffers. 1.3734 + * 1.3735 + * The visible and valid regions of the ThebesLayer are computed without 1.3736 + * knowing the residual transform (because we don't know what the residual 1.3737 + * transform is going to be until we've built the layer tree!). So we have to 1.3738 + * consider whether content painted in the range [x, xmost) might be painted 1.3739 + * outside the visible region we computed for that content. The visible region 1.3740 + * would be [floor(x), ceil(xmost)). The content would be rendered at 1.3741 + * [x + r, xmost + r), where -0.5 <= r < 0.5. So some half-rendered pixels could 1.3742 + * indeed fall outside the computed visible region, which is not a big deal; 1.3743 + * similar issues already arise when we snap cliprects to nearest pixels. 1.3744 + * Note that if the rendering of the content is snapped to nearest pixels --- 1.3745 + * which it often is --- then the content is actually rendered at 1.3746 + * [snap(x + r), snap(xmost + r)). It turns out that floor(x) <= snap(x + r) 1.3747 + * and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content 1.3748 + * always falls within the visible region we computed. 1.3749 + */ 1.3750 + 1.3751 +/* static */ void 1.3752 +FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, 1.3753 + gfxContext* aContext, 1.3754 + const nsIntRegion& aRegionToDraw, 1.3755 + DrawRegionClip aClip, 1.3756 + const nsIntRegion& aRegionToInvalidate, 1.3757 + void* aCallbackData) 1.3758 +{ 1.3759 + PROFILER_LABEL("gfx", "DrawThebesLayer"); 1.3760 + 1.3761 + nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*> 1.3762 + (aCallbackData); 1.3763 + 1.3764 + FrameLayerBuilder *layerBuilder = aLayer->Manager()->GetLayerBuilder(); 1.3765 + NS_ASSERTION(layerBuilder, "Unexpectedly null layer builder!"); 1.3766 + 1.3767 + if (layerBuilder->CheckDOMModified()) 1.3768 + return; 1.3769 + 1.3770 + ThebesLayerItemsEntry* entry = layerBuilder->mThebesLayerItems.GetEntry(aLayer); 1.3771 + NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!"); 1.3772 + if (!entry->mContainerLayerFrame) { 1.3773 + return; 1.3774 + } 1.3775 + 1.3776 + 1.3777 + ThebesDisplayItemLayerUserData* userData = 1.3778 + static_cast<ThebesDisplayItemLayerUserData*> 1.3779 + (aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); 1.3780 + NS_ASSERTION(userData, "where did our user data go?"); 1.3781 + 1.3782 + bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip); 1.3783 + 1.3784 + if (!shouldDrawRectsSeparately) { 1.3785 + if (aClip == DrawRegionClip::DRAW_SNAPPED) { 1.3786 + gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw); 1.3787 + } else if (aClip == DrawRegionClip::DRAW) { 1.3788 + gfxUtils::ClipToRegion(aContext, aRegionToDraw); 1.3789 + } 1.3790 + 1.3791 + DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor); 1.3792 + } 1.3793 + 1.3794 + // make the origin of the context coincide with the origin of the 1.3795 + // ThebesLayer 1.3796 + gfxContextMatrixAutoSaveRestore saveMatrix(aContext); 1.3797 + nsIntPoint offset = GetTranslationForThebesLayer(aLayer); 1.3798 + 1.3799 + nsPresContext* presContext = entry->mContainerLayerFrame->PresContext(); 1.3800 + int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); 1.3801 + 1.3802 + RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw, 1.3803 + offset, appUnitsPerDevPixel, 1.3804 + userData->mXScale, userData->mYScale); 1.3805 + 1.3806 + nsRefPtr<nsRenderingContext> rc = new nsRenderingContext(); 1.3807 + rc->Init(presContext->DeviceContext(), aContext); 1.3808 + 1.3809 + if (shouldDrawRectsSeparately) { 1.3810 + nsIntRegionRectIterator it(aRegionToDraw); 1.3811 + while (const nsIntRect* iterRect = it.Next()) { 1.3812 + gfxContextAutoSaveRestore save(aContext); 1.3813 + aContext->NewPath(); 1.3814 + aContext->Rectangle(*iterRect, aClip == DrawRegionClip::DRAW_SNAPPED); 1.3815 + aContext->Clip(); 1.3816 + 1.3817 + DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor); 1.3818 + 1.3819 + // Apply the residual transform if it has been enabled, to ensure that 1.3820 + // snapping when we draw into aContext exactly matches the ideal transform. 1.3821 + // See above for why this is OK. 1.3822 + aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)); 1.3823 + aContext->Scale(userData->mXScale, userData->mYScale); 1.3824 + 1.3825 + layerBuilder->PaintItems(entry->mItems, *iterRect, aContext, rc, 1.3826 + builder, presContext, 1.3827 + offset, userData->mXScale, userData->mYScale, 1.3828 + entry->mCommonClipCount); 1.3829 + } 1.3830 + } else { 1.3831 + // Apply the residual transform if it has been enabled, to ensure that 1.3832 + // snapping when we draw into aContext exactly matches the ideal transform. 1.3833 + // See above for why this is OK. 1.3834 + aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)); 1.3835 + aContext->Scale(userData->mXScale, userData->mYScale); 1.3836 + 1.3837 + layerBuilder->PaintItems(entry->mItems, aRegionToDraw.GetBounds(), aContext, rc, 1.3838 + builder, presContext, 1.3839 + offset, userData->mXScale, userData->mYScale, 1.3840 + entry->mCommonClipCount); 1.3841 + } 1.3842 + 1.3843 + if (presContext->GetPaintFlashing()) { 1.3844 + FlashPaint(aContext); 1.3845 + } 1.3846 + 1.3847 + if (!aRegionToInvalidate.IsEmpty()) { 1.3848 + aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds()); 1.3849 + } 1.3850 +} 1.3851 + 1.3852 +bool 1.3853 +FrameLayerBuilder::CheckDOMModified() 1.3854 +{ 1.3855 + if (!mRootPresContext || 1.3856 + mInitialDOMGeneration == mRootPresContext->GetDOMGeneration()) 1.3857 + return false; 1.3858 + if (mDetectedDOMModification) { 1.3859 + // Don't spam the console with extra warnings 1.3860 + return true; 1.3861 + } 1.3862 + mDetectedDOMModification = true; 1.3863 + // Painting is not going to complete properly. There's not much 1.3864 + // we can do here though. Invalidating the window to get another repaint 1.3865 + // is likely to lead to an infinite repaint loop. 1.3866 + NS_WARNING("Detected DOM modification during paint, bailing out!"); 1.3867 + return true; 1.3868 +} 1.3869 + 1.3870 +#ifdef MOZ_DUMP_PAINTING 1.3871 +/* static */ void 1.3872 +FrameLayerBuilder::DumpRetainedLayerTree(LayerManager* aManager, FILE* aFile, bool aDumpHtml) 1.3873 +{ 1.3874 + aManager->Dump(aFile, "", aDumpHtml); 1.3875 +} 1.3876 +#endif 1.3877 + 1.3878 +gfx::Rect 1.3879 +CalculateBounds(const nsTArray<DisplayItemClip::RoundedRect>& aRects, int32_t A2D) 1.3880 +{ 1.3881 + nsRect bounds = aRects[0].mRect; 1.3882 + for (uint32_t i = 1; i < aRects.Length(); ++i) { 1.3883 + bounds.UnionRect(bounds, aRects[i].mRect); 1.3884 + } 1.3885 + 1.3886 + return gfx::ToRect(nsLayoutUtils::RectToGfxRect(bounds, A2D)); 1.3887 +} 1.3888 + 1.3889 +static void 1.3890 +SetClipCount(ThebesDisplayItemLayerUserData* aThebesData, 1.3891 + uint32_t aClipCount) 1.3892 +{ 1.3893 + if (aThebesData) { 1.3894 + aThebesData->mMaskClipCount = aClipCount; 1.3895 + } 1.3896 +} 1.3897 + 1.3898 +void 1.3899 +ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip, 1.3900 + uint32_t aRoundedRectClipCount) 1.3901 +{ 1.3902 + // if the number of clips we are going to mask has decreased, then aLayer might have 1.3903 + // cached graphics which assume the existence of a soon-to-be non-existent mask layer 1.3904 + // in that case, invalidate the whole layer. 1.3905 + ThebesDisplayItemLayerUserData* thebesData = GetThebesDisplayItemLayerUserData(aLayer); 1.3906 + if (thebesData && 1.3907 + aRoundedRectClipCount < thebesData->mMaskClipCount) { 1.3908 + ThebesLayer* thebes = aLayer->AsThebesLayer(); 1.3909 + thebes->InvalidateRegion(thebes->GetValidRegion().GetBounds()); 1.3910 + } 1.3911 + 1.3912 + // don't build an unnecessary mask 1.3913 + nsIntRect layerBounds = aLayer->GetVisibleRegion().GetBounds(); 1.3914 + if (aClip.GetRoundedRectCount() == 0 || 1.3915 + aRoundedRectClipCount == 0 || 1.3916 + layerBounds.IsEmpty()) { 1.3917 + SetClipCount(thebesData, 0); 1.3918 + return; 1.3919 + } 1.3920 + 1.3921 + // check if we can re-use the mask layer 1.3922 + nsRefPtr<ImageLayer> maskLayer = CreateOrRecycleMaskImageLayerFor(aLayer); 1.3923 + MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer); 1.3924 + 1.3925 + MaskLayerUserData newData; 1.3926 + aClip.AppendRoundedRects(&newData.mRoundedClipRects, aRoundedRectClipCount); 1.3927 + newData.mScaleX = mParameters.mXScale; 1.3928 + newData.mScaleY = mParameters.mYScale; 1.3929 + newData.mOffset = mParameters.mOffset; 1.3930 + newData.mAppUnitsPerDevPixel = mContainerFrame->PresContext()->AppUnitsPerDevPixel(); 1.3931 + 1.3932 + if (*userData == newData) { 1.3933 + aLayer->SetMaskLayer(maskLayer); 1.3934 + SetClipCount(thebesData, aRoundedRectClipCount); 1.3935 + return; 1.3936 + } 1.3937 + 1.3938 + // calculate a more precise bounding rect 1.3939 + gfx::Rect boundingRect = CalculateBounds(newData.mRoundedClipRects, 1.3940 + newData.mAppUnitsPerDevPixel); 1.3941 + boundingRect.Scale(mParameters.mXScale, mParameters.mYScale); 1.3942 + 1.3943 + uint32_t maxSize = mManager->GetMaxTextureSize(); 1.3944 + NS_ASSERTION(maxSize > 0, "Invalid max texture size"); 1.3945 + gfx::Size surfaceSize(std::min<gfx::Float>(boundingRect.Width(), maxSize), 1.3946 + std::min<gfx::Float>(boundingRect.Height(), maxSize)); 1.3947 + 1.3948 + // maskTransform is applied to the clip when it is painted into the mask (as a 1.3949 + // component of imageTransform), and its inverse used when the mask is used for 1.3950 + // masking. 1.3951 + // It is the transform from the masked layer's space to mask space 1.3952 + gfx::Matrix maskTransform; 1.3953 + maskTransform.Scale(surfaceSize.width/boundingRect.Width(), 1.3954 + surfaceSize.height/boundingRect.Height()); 1.3955 + gfx::Point p = boundingRect.TopLeft(); 1.3956 + maskTransform.Translate(-p.x, -p.y); 1.3957 + // imageTransform is only used when the clip is painted to the mask 1.3958 + gfx::Matrix imageTransform = maskTransform; 1.3959 + imageTransform.Scale(mParameters.mXScale, mParameters.mYScale); 1.3960 + 1.3961 + nsAutoPtr<MaskLayerImageCache::MaskLayerImageKey> newKey( 1.3962 + new MaskLayerImageCache::MaskLayerImageKey()); 1.3963 + 1.3964 + // copy and transform the rounded rects 1.3965 + for (uint32_t i = 0; i < newData.mRoundedClipRects.Length(); ++i) { 1.3966 + newKey->mRoundedClipRects.AppendElement( 1.3967 + MaskLayerImageCache::PixelRoundedRect(newData.mRoundedClipRects[i], 1.3968 + mContainerFrame->PresContext())); 1.3969 + newKey->mRoundedClipRects[i].ScaleAndTranslate(imageTransform); 1.3970 + } 1.3971 + 1.3972 + const MaskLayerImageCache::MaskLayerImageKey* lookupKey = newKey; 1.3973 + 1.3974 + // check to see if we can reuse a mask image 1.3975 + nsRefPtr<ImageContainer> container = 1.3976 + GetMaskLayerImageCache()->FindImageFor(&lookupKey); 1.3977 + 1.3978 + if (!container) { 1.3979 + IntSize surfaceSizeInt(NSToIntCeil(surfaceSize.width), 1.3980 + NSToIntCeil(surfaceSize.height)); 1.3981 + // no existing mask image, so build a new one 1.3982 + RefPtr<DrawTarget> dt = 1.3983 + aLayer->Manager()->CreateOptimalMaskDrawTarget(surfaceSizeInt); 1.3984 + 1.3985 + // fail if we can't get the right surface 1.3986 + if (!dt) { 1.3987 + NS_WARNING("Could not create DrawTarget for mask layer."); 1.3988 + SetClipCount(thebesData, 0); 1.3989 + return; 1.3990 + } 1.3991 + 1.3992 + nsRefPtr<gfxContext> context = new gfxContext(dt); 1.3993 + context->Multiply(ThebesMatrix(imageTransform)); 1.3994 + 1.3995 + // paint the clipping rects with alpha to create the mask 1.3996 + context->SetColor(gfxRGBA(1, 1, 1, 1)); 1.3997 + aClip.DrawRoundedRectsTo(context, 1.3998 + newData.mAppUnitsPerDevPixel, 1.3999 + 0, 1.4000 + aRoundedRectClipCount); 1.4001 + 1.4002 + RefPtr<SourceSurface> surface = dt->Snapshot(); 1.4003 + 1.4004 + // build the image and container 1.4005 + container = aLayer->Manager()->CreateImageContainer(); 1.4006 + NS_ASSERTION(container, "Could not create image container for mask layer."); 1.4007 + nsRefPtr<Image> image = container->CreateImage(ImageFormat::CAIRO_SURFACE); 1.4008 + NS_ASSERTION(image, "Could not create image container for mask layer."); 1.4009 + CairoImage::Data data; 1.4010 + data.mSize = surfaceSizeInt; 1.4011 + data.mSourceSurface = surface; 1.4012 + 1.4013 + static_cast<CairoImage*>(image.get())->SetData(data); 1.4014 + container->SetCurrentImageInTransaction(image); 1.4015 + 1.4016 + GetMaskLayerImageCache()->PutImage(newKey.forget(), container); 1.4017 + } 1.4018 + 1.4019 + maskLayer->SetContainer(container); 1.4020 + 1.4021 + maskTransform.Invert(); 1.4022 + Matrix4x4 matrix = Matrix4x4::From2D(maskTransform); 1.4023 + matrix.Translate(mParameters.mOffset.x, mParameters.mOffset.y, 0); 1.4024 + maskLayer->SetBaseTransform(matrix); 1.4025 + 1.4026 + // save the details of the clip in user data 1.4027 + userData->mScaleX = newData.mScaleX; 1.4028 + userData->mScaleY = newData.mScaleY; 1.4029 + userData->mOffset = newData.mOffset; 1.4030 + userData->mAppUnitsPerDevPixel = newData.mAppUnitsPerDevPixel; 1.4031 + userData->mRoundedClipRects.SwapElements(newData.mRoundedClipRects); 1.4032 + userData->mImageKey = lookupKey; 1.4033 + 1.4034 + aLayer->SetMaskLayer(maskLayer); 1.4035 + SetClipCount(thebesData, aRoundedRectClipCount); 1.4036 + return; 1.4037 +} 1.4038 + 1.4039 +} // namespace mozilla