1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "TiledContentHost.h"
7 #include "gfxPrefs.h"                   // for gfxPrefs
8 #include "PaintedLayerComposite.h"      // for PaintedLayerComposite
9 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
10 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
11 #include "mozilla/gfx/Point.h"          // for IntSize
12 #include "mozilla/layers/Compositor.h"  // for Compositor
13 //#include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent
14 #include "mozilla/layers/Effects.h"     // for TexturedEffect, Effect, etc
15 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
16 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
17 #include "nsAString.h"
18 #include "nsDebug.h"                    // for NS_WARNING
19 #include "nsPoint.h"                    // for IntPoint
20 #include "nsPrintfCString.h"            // for nsPrintfCString
21 #include "nsRect.h"                     // for IntRect
22 #include "mozilla/layers/TextureClient.h"
23 
24 namespace mozilla {
25 using namespace gfx;
26 namespace layers {
27 
28 class Layer;
29 
30 float
GetFadeInOpacity(float aOpacity)31 TileHost::GetFadeInOpacity(float aOpacity)
32 {
33   TimeStamp now = TimeStamp::Now();
34   if (!gfxPrefs::LayerTileFadeInEnabled() ||
35       mFadeStart.IsNull() ||
36       now < mFadeStart)
37   {
38     return aOpacity;
39   }
40 
41   float duration = gfxPrefs::LayerTileFadeInDuration();
42   float elapsed = (now - mFadeStart).ToMilliseconds();
43   if (elapsed > duration) {
44     mFadeStart = TimeStamp();
45     return aOpacity;
46   }
47   return aOpacity * (elapsed / duration);
48 }
49 
TiledLayerBufferComposite()50 TiledLayerBufferComposite::TiledLayerBufferComposite()
51   : mFrameResolution()
52 {}
53 
~TiledLayerBufferComposite()54 TiledLayerBufferComposite::~TiledLayerBufferComposite()
55 {
56   Clear();
57 }
58 
59 void
SetCompositor(Compositor * aCompositor)60 TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
61 {
62   MOZ_ASSERT(aCompositor);
63   for (TileHost& tile : mRetainedTiles) {
64     if (tile.IsPlaceholderTile()) continue;
65     tile.mTextureHost->SetCompositor(aCompositor);
66     if (tile.mTextureHostOnWhite) {
67       tile.mTextureHostOnWhite->SetCompositor(aCompositor);
68     }
69   }
70 }
71 
72 void
AddAnimationInvalidation(nsIntRegion & aRegion)73 TiledLayerBufferComposite::AddAnimationInvalidation(nsIntRegion& aRegion)
74 {
75   // We need to invalidate rects where we have a tile that is in the
76   // process of fading in.
77   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
78     if (!mRetainedTiles[i].mFadeStart.IsNull()) {
79       TileIntPoint position = mTiles.TilePosition(i);
80       IntPoint offset = GetTileOffset(position);
81       nsIntRegion tileRegion = IntRect(offset, GetScaledTileSize());
82       aRegion.OrWith(tileRegion);
83     }
84   }
85 }
86 
TiledContentHost(const TextureInfo & aTextureInfo)87 TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
88   : ContentHost(aTextureInfo)
89   , mTiledBuffer(TiledLayerBufferComposite())
90   , mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
91 {
92   MOZ_COUNT_CTOR(TiledContentHost);
93 }
94 
~TiledContentHost()95 TiledContentHost::~TiledContentHost()
96 {
97   MOZ_COUNT_DTOR(TiledContentHost);
98 }
99 
100 already_AddRefed<TexturedEffect>
GenEffect(const gfx::SamplingFilter aSamplingFilter)101 TiledContentHost::GenEffect(const gfx::SamplingFilter aSamplingFilter)
102 {
103   // If we can use hwc for this TiledContentHost, it implies that we have exactly
104   // one high precision tile. Please check TiledContentHost::GetRenderState() for
105   // all condition.
106   MOZ_ASSERT(mTiledBuffer.GetTileCount() == 1 && mLowPrecisionTiledBuffer.GetTileCount() == 0);
107   MOZ_ASSERT(mTiledBuffer.GetTile(0).mTextureHost);
108 
109   TileHost& tile = mTiledBuffer.GetTile(0);
110   if (!tile.mTextureHost->BindTextureSource(tile.mTextureSource)) {
111     return nullptr;
112   }
113 
114   return CreateTexturedEffect(tile.mTextureSource,
115                               nullptr,
116                               aSamplingFilter,
117                               true,
118                               tile.mTextureHost->GetRenderState());
119 }
120 
121 void
Attach(Layer * aLayer,Compositor * aCompositor,AttachFlags aFlags)122 TiledContentHost::Attach(Layer* aLayer,
123                          Compositor* aCompositor,
124                          AttachFlags aFlags /* = NO_FLAGS */)
125 {
126   CompositableHost::Attach(aLayer, aCompositor, aFlags);
127 }
128 
129 void
Detach(Layer * aLayer,AttachFlags aFlags)130 TiledContentHost::Detach(Layer* aLayer,
131                          AttachFlags aFlags /* = NO_FLAGS */)
132 {
133   if (!mKeepAttached || aLayer == mLayer || aFlags & FORCE_DETACH) {
134     // Clear the TiledLayerBuffers, which will take care of releasing the
135     // copy-on-write locks.
136     mTiledBuffer.Clear();
137     mLowPrecisionTiledBuffer.Clear();
138   }
139   CompositableHost::Detach(aLayer,aFlags);
140 }
141 
142 bool
UseTiledLayerBuffer(ISurfaceAllocator * aAllocator,const SurfaceDescriptorTiles & aTiledDescriptor)143 TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
144                                       const SurfaceDescriptorTiles& aTiledDescriptor)
145 {
146   if (aTiledDescriptor.resolution() < 1) {
147     if (!mLowPrecisionTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
148       return false;
149     }
150   } else {
151     if (!mTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
152       return false;
153     }
154   }
155   return true;
156 }
157 
158 void
UseTileTexture(CompositableTextureHostRef & aTexture,CompositableTextureSourceRef & aTextureSource,const IntRect & aUpdateRect,Compositor * aCompositor)159 UseTileTexture(CompositableTextureHostRef& aTexture,
160                CompositableTextureSourceRef& aTextureSource,
161                const IntRect& aUpdateRect,
162                Compositor* aCompositor)
163 {
164   MOZ_ASSERT(aTexture);
165   if (!aTexture) {
166     return;
167   }
168 
169   if (aCompositor) {
170     aTexture->SetCompositor(aCompositor);
171   }
172 
173   if (!aUpdateRect.IsEmpty()) {
174     // For !HasIntermediateBuffer() textures, this is likely a no-op.
175     nsIntRegion region = aUpdateRect;
176     aTexture->Updated(&region);
177   }
178 
179   aTexture->PrepareTextureSource(aTextureSource);
180 }
181 
182 class TextureSourceRecycler
183 {
184 public:
TextureSourceRecycler(nsTArray<TileHost> && aTileSet)185   explicit TextureSourceRecycler(nsTArray<TileHost>&& aTileSet)
186     : mTiles(Move(aTileSet))
187     , mFirstPossibility(0)
188   {}
189 
190   // Attempts to recycle a texture source that is already bound to the
191   // texture host for aTile.
RecycleTextureSourceForTile(TileHost & aTile)192   void RecycleTextureSourceForTile(TileHost& aTile) {
193     for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
194       // Skip over existing tiles without a retained texture source
195       // and make sure we don't iterate them in the future.
196       if (!mTiles[i].mTextureSource) {
197         if (i == mFirstPossibility) {
198           mFirstPossibility++;
199         }
200         continue;
201       }
202 
203       // If this tile matches, then copy across the retained texture source (if
204       // any).
205       if (aTile.mTextureHost == mTiles[i].mTextureHost) {
206         aTile.mTextureSource = Move(mTiles[i].mTextureSource);
207         if (aTile.mTextureHostOnWhite) {
208           aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
209         }
210         break;
211       }
212     }
213   }
214 
215   // Attempts to recycle any texture source to avoid needing to allocate
216   // a new one.
RecycleTextureSource(TileHost & aTile)217   void RecycleTextureSource(TileHost& aTile) {
218     for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
219       if (!mTiles[i].mTextureSource) {
220         if (i == mFirstPossibility) {
221           mFirstPossibility++;
222         }
223         continue;
224       }
225 
226       if (mTiles[i].mTextureSource &&
227           mTiles[i].mTextureHost->GetFormat() == aTile.mTextureHost->GetFormat()) {
228         aTile.mTextureSource = Move(mTiles[i].mTextureSource);
229         if (aTile.mTextureHostOnWhite) {
230           aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
231         }
232         break;
233       }
234     }
235   }
236 
RecycleTileFading(TileHost & aTile)237   void RecycleTileFading(TileHost& aTile) {
238     for (size_t i = 0; i < mTiles.Length(); i++) {
239       if (mTiles[i].mTextureHost == aTile.mTextureHost) {
240         aTile.mFadeStart = mTiles[i].mFadeStart;
241       }
242     }
243   }
244 
245 protected:
246   nsTArray<TileHost> mTiles;
247   size_t mFirstPossibility;
248 };
249 
250 bool
UseTiles(const SurfaceDescriptorTiles & aTiles,Compositor * aCompositor,ISurfaceAllocator * aAllocator)251 TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
252                                     Compositor* aCompositor,
253                                     ISurfaceAllocator* aAllocator)
254 {
255   if (mResolution != aTiles.resolution() ||
256       aTiles.tileSize() != mTileSize) {
257     Clear();
258   }
259   MOZ_ASSERT(aAllocator);
260   MOZ_ASSERT(aCompositor);
261   if (!aAllocator || !aCompositor) {
262     return false;
263   }
264 
265   if (aTiles.resolution() == 0 || IsNaN(aTiles.resolution())) {
266     // There are divisions by mResolution so this protects the compositor process
267     // against malicious content processes and fuzzing.
268     return false;
269   }
270 
271   TilesPlacement newTiles(aTiles.firstTileX(), aTiles.firstTileY(),
272                           aTiles.retainedWidth(), aTiles.retainedHeight());
273 
274   const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();
275 
276   TextureSourceRecycler oldRetainedTiles(Move(mRetainedTiles));
277   mRetainedTiles.SetLength(tileDescriptors.Length());
278 
279   // Step 1, deserialize the incoming set of tiles into mRetainedTiles, and attempt
280   // to recycle the TextureSource for any repeated tiles.
281   //
282   // Since we don't have any retained 'tile' object, we have to search for instances
283   // of the same TextureHost in the old tile set. The cost of binding a TextureHost
284   // to a TextureSource for gralloc (binding EGLImage to GL texture) can be really
285   // high, so we avoid this whenever possible.
286   for (size_t i = 0; i < tileDescriptors.Length(); i++) {
287     const TileDescriptor& tileDesc = tileDescriptors[i];
288 
289     TileHost& tile = mRetainedTiles[i];
290 
291     if (tileDesc.type() != TileDescriptor::TTexturedTileDescriptor) {
292       NS_WARNING_ASSERTION(
293         tileDesc.type() == TileDescriptor::TPlaceholderTileDescriptor,
294         "Unrecognised tile descriptor type");
295       continue;
296     }
297 
298     const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
299 
300     tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
301     tile.mTextureHost->SetCompositor(aCompositor);
302     tile.mTextureHost->DeserializeReadLock(texturedDesc.sharedLock(), aAllocator);
303 
304     if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
305       tile.mTextureHostOnWhite = TextureHost::AsTextureHost(
306         texturedDesc.textureOnWhite().get_PTextureParent()
307       );
308       tile.mTextureHostOnWhite->DeserializeReadLock(
309         texturedDesc.sharedLockOnWhite(), aAllocator
310       );
311     }
312 
313     tile.mTilePosition = newTiles.TilePosition(i);
314 
315     // If this same tile texture existed in the old tile set then this will move the texture
316     // source into our new tile.
317     oldRetainedTiles.RecycleTextureSourceForTile(tile);
318 
319     // If this tile is in the process of fading, we need to keep that going
320     oldRetainedTiles.RecycleTileFading(tile);
321 
322     if (aTiles.isProgressive() &&
323         texturedDesc.wasPlaceholder())
324     {
325       // This is a progressive paint, and the tile used to be a placeholder.
326       // We need to begin fading it in (if enabled via layers.tiles.fade-in.enabled)
327       tile.mFadeStart = TimeStamp::Now();
328 
329       aCompositor->CompositeUntil(tile.mFadeStart +
330         TimeDuration::FromMilliseconds(gfxPrefs::LayerTileFadeInDuration()));
331     }
332   }
333 
334   // Step 2, attempt to recycle unused texture sources from the old tile set into new tiles.
335   //
336   // For gralloc, binding a new TextureHost to the existing TextureSource is the fastest way
337   // to ensure that any implicit locking on the old gralloc image is released.
338   for (TileHost& tile : mRetainedTiles) {
339     if (!tile.mTextureHost || tile.mTextureSource) {
340       continue;
341     }
342     oldRetainedTiles.RecycleTextureSource(tile);
343   }
344 
345   // Step 3, handle the texture uploads, texture source binding and release the
346   // copy-on-write locks for textures with an internal buffer.
347   for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
348     TileHost& tile = mRetainedTiles[i];
349     if (!tile.mTextureHost) {
350       continue;
351     }
352 
353     const TileDescriptor& tileDesc = tileDescriptors[i];
354     const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
355 
356     UseTileTexture(tile.mTextureHost,
357                    tile.mTextureSource,
358                    texturedDesc.updateRect(),
359                    aCompositor);
360 
361     if (tile.mTextureHostOnWhite) {
362       UseTileTexture(tile.mTextureHostOnWhite,
363                      tile.mTextureSourceOnWhite,
364                      texturedDesc.updateRect(),
365                      aCompositor);
366     }
367   }
368 
369   mTiles = newTiles;
370   mTileSize = aTiles.tileSize();
371   mTileOrigin = aTiles.tileOrigin();
372   mValidRegion = aTiles.validRegion();
373   mResolution = aTiles.resolution();
374   mFrameResolution = CSSToParentLayerScale2D(aTiles.frameXResolution(),
375                                              aTiles.frameYResolution());
376 
377   return true;
378 }
379 
380 void
Clear()381 TiledLayerBufferComposite::Clear()
382 {
383   mRetainedTiles.Clear();
384   mTiles.mFirst = TileIntPoint();
385   mTiles.mSize = TileIntSize();
386   mValidRegion = nsIntRegion();
387   mResolution = 1.0;
388 }
389 
390 void
Composite(LayerComposite * aLayer,EffectChain & aEffectChain,float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::SamplingFilter aSamplingFilter,const gfx::IntRect & aClipRect,const nsIntRegion * aVisibleRegion)391 TiledContentHost::Composite(LayerComposite* aLayer,
392                             EffectChain& aEffectChain,
393                             float aOpacity,
394                             const gfx::Matrix4x4& aTransform,
395                             const gfx::SamplingFilter aSamplingFilter,
396                             const gfx::IntRect& aClipRect,
397                             const nsIntRegion* aVisibleRegion /* = nullptr */)
398 {
399   MOZ_ASSERT(mCompositor);
400   // Reduce the opacity of the low-precision buffer to make it a
401   // little more subtle and less jarring. In particular, text
402   // rendered at low-resolution and scaled tends to look pretty
403   // heavy and this helps mitigate that. When we reduce the opacity
404   // we also make sure to draw the background color behind the
405   // reduced-opacity tile so that content underneath doesn't show
406   // through.
407   // However, in cases where the background is transparent, or the layer
408   // already has some opacity, we want to skip this behaviour. Otherwise
409   // we end up changing the expected overall transparency of the content,
410   // and it just looks wrong.
411   Color backgroundColor;
412   if (aOpacity == 1.0f && gfxPrefs::LowPrecisionOpacity() < 1.0f) {
413     // Background colors are only stored on scrollable layers. Grab
414     // the one from the nearest scrollable ancestor layer.
415     for (LayerMetricsWrapper ancestor(GetLayer(), LayerMetricsWrapper::StartAt::BOTTOM); ancestor; ancestor = ancestor.GetParent()) {
416       if (ancestor.Metrics().IsScrollable()) {
417         backgroundColor = ancestor.Metadata().GetBackgroundColor();
418         break;
419       }
420     }
421   }
422   float lowPrecisionOpacityReduction =
423         (aOpacity == 1.0f && backgroundColor.a == 1.0f)
424         ? gfxPrefs::LowPrecisionOpacity() : 1.0f;
425 
426   nsIntRegion tmpRegion;
427   const nsIntRegion* renderRegion = aVisibleRegion;
428 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
429   if (PaintWillResample()) {
430     // If we're resampling, then the texture image will contain exactly the
431     // entire visible region's bounds, and we should draw it all in one quad
432     // to avoid unexpected aliasing.
433     tmpRegion = aVisibleRegion->GetBounds();
434     renderRegion = &tmpRegion;
435   }
436 #endif
437 
438   // Render the low and high precision buffers.
439   RenderLayerBuffer(mLowPrecisionTiledBuffer,
440                     lowPrecisionOpacityReduction < 1.0f ? &backgroundColor : nullptr,
441                     aEffectChain, lowPrecisionOpacityReduction * aOpacity,
442                     aSamplingFilter, aClipRect, *renderRegion, aTransform);
443   RenderLayerBuffer(mTiledBuffer, nullptr, aEffectChain, aOpacity, aSamplingFilter,
444                     aClipRect, *renderRegion, aTransform);
445 }
446 
447 
448 void
RenderTile(TileHost & aTile,EffectChain & aEffectChain,float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::SamplingFilter aSamplingFilter,const gfx::IntRect & aClipRect,const nsIntRegion & aScreenRegion,const IntPoint & aTextureOffset,const IntSize & aTextureBounds,const gfx::Rect & aVisibleRect)449 TiledContentHost::RenderTile(TileHost& aTile,
450                              EffectChain& aEffectChain,
451                              float aOpacity,
452                              const gfx::Matrix4x4& aTransform,
453                              const gfx::SamplingFilter aSamplingFilter,
454                              const gfx::IntRect& aClipRect,
455                              const nsIntRegion& aScreenRegion,
456                              const IntPoint& aTextureOffset,
457                              const IntSize& aTextureBounds,
458                              const gfx::Rect& aVisibleRect)
459 {
460   MOZ_ASSERT(!aTile.IsPlaceholderTile());
461 
462   AutoLockTextureHost autoLock(aTile.mTextureHost);
463   AutoLockTextureHost autoLockOnWhite(aTile.mTextureHostOnWhite);
464   if (autoLock.Failed() ||
465       autoLockOnWhite.Failed()) {
466     NS_WARNING("Failed to lock tile");
467     return;
468   }
469 
470   if (!aTile.mTextureHost->BindTextureSource(aTile.mTextureSource)) {
471     return;
472   }
473 
474   if (aTile.mTextureHostOnWhite && !aTile.mTextureHostOnWhite->BindTextureSource(aTile.mTextureSourceOnWhite)) {
475     return;
476   }
477 
478   RefPtr<TexturedEffect> effect =
479     CreateTexturedEffect(aTile.mTextureSource,
480                          aTile.mTextureSourceOnWhite,
481                          aSamplingFilter,
482                          true,
483                          aTile.mTextureHost->GetRenderState());
484   if (!effect) {
485     return;
486   }
487 
488   float opacity = aTile.GetFadeInOpacity(aOpacity);
489   aEffectChain.mPrimaryEffect = effect;
490 
491   for (auto iter = aScreenRegion.RectIter(); !iter.Done(); iter.Next()) {
492     const IntRect& rect = iter.Get();
493     Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
494     Rect textureRect(rect.x - aTextureOffset.x, rect.y - aTextureOffset.y,
495                      rect.width, rect.height);
496 
497     effect->mTextureCoords = Rect(textureRect.x / aTextureBounds.width,
498                                   textureRect.y / aTextureBounds.height,
499                                   textureRect.width / aTextureBounds.width,
500                                   textureRect.height / aTextureBounds.height);
501     mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, opacity, aTransform, aVisibleRect);
502   }
503   DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
504   if (aTile.mTextureHostOnWhite) {
505     flags |= DiagnosticFlags::COMPONENT_ALPHA;
506   }
507   mCompositor->DrawDiagnostics(flags,
508                                aScreenRegion, aClipRect, aTransform, mFlashCounter);
509 }
510 
511 void
RenderLayerBuffer(TiledLayerBufferComposite & aLayerBuffer,const Color * aBackgroundColor,EffectChain & aEffectChain,float aOpacity,const gfx::SamplingFilter aSamplingFilter,const gfx::IntRect & aClipRect,nsIntRegion aVisibleRegion,gfx::Matrix4x4 aTransform)512 TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
513                                     const Color* aBackgroundColor,
514                                     EffectChain& aEffectChain,
515                                     float aOpacity,
516                                     const gfx::SamplingFilter aSamplingFilter,
517                                     const gfx::IntRect& aClipRect,
518                                     nsIntRegion aVisibleRegion,
519                                     gfx::Matrix4x4 aTransform)
520 {
521   if (!mCompositor) {
522     NS_WARNING("Can't render tiled content host - no compositor");
523     return;
524   }
525   float resolution = aLayerBuffer.GetResolution();
526   gfx::Size layerScale(1, 1);
527 
528   // We assume that the current frame resolution is the one used in our high
529   // precision layer buffer. Compensate for a changing frame resolution when
530   // rendering the low precision buffer.
531   if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
532     const CSSToParentLayerScale2D& layerResolution = aLayerBuffer.GetFrameResolution();
533     const CSSToParentLayerScale2D& localResolution = mTiledBuffer.GetFrameResolution();
534     layerScale.width = layerResolution.xScale / localResolution.xScale;
535     layerScale.height = layerResolution.yScale / localResolution.yScale;
536     aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height);
537   }
538 
539   // Make sure we don't render at low resolution where we have valid high
540   // resolution content, to avoid overdraw and artifacts with semi-transparent
541   // layers.
542   nsIntRegion maskRegion;
543   if (resolution != mTiledBuffer.GetResolution()) {
544     maskRegion = mTiledBuffer.GetValidRegion();
545     // XXX This should be ScaleRoundIn, but there is no such function on
546     //     nsIntRegion.
547     maskRegion.ScaleRoundOut(layerScale.width, layerScale.height);
548   }
549 
550   // Make sure the resolution and difference in frame resolution are accounted
551   // for in the layer transform.
552   aTransform.PreScale(1/(resolution * layerScale.width),
553                       1/(resolution * layerScale.height), 1);
554 
555   DiagnosticFlags componentAlphaDiagnostic = DiagnosticFlags::NO_DIAGNOSTIC;
556 
557   nsIntRegion compositeRegion = aLayerBuffer.GetValidRegion();
558   compositeRegion.AndWith(aVisibleRegion);
559   compositeRegion.SubOut(maskRegion);
560 
561   IntRect visibleRect = aVisibleRegion.GetBounds();
562 
563   if (compositeRegion.IsEmpty()) {
564     return;
565   }
566 
567   if (aBackgroundColor) {
568     nsIntRegion backgroundRegion = compositeRegion;
569     backgroundRegion.ScaleRoundOut(resolution, resolution);
570     EffectChain effect;
571     effect.mPrimaryEffect = new EffectSolidColor(*aBackgroundColor);
572     for (auto iter = backgroundRegion.RectIter(); !iter.Done(); iter.Next()) {
573       const IntRect& rect = iter.Get();
574       Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
575       mCompositor->DrawQuad(graphicsRect, aClipRect, effect, 1.0, aTransform);
576     }
577   }
578 
579   for (size_t i = 0; i < aLayerBuffer.GetTileCount(); ++i) {
580     TileHost& tile = aLayerBuffer.GetTile(i);
581     if (tile.IsPlaceholderTile()) {
582       continue;
583     }
584 
585     TileIntPoint tilePosition = aLayerBuffer.GetPlacement().TilePosition(i);
586     // A sanity check that catches a lot of mistakes.
587     MOZ_ASSERT(tilePosition.x == tile.mTilePosition.x && tilePosition.y == tile.mTilePosition.y);
588 
589     IntPoint tileOffset = aLayerBuffer.GetTileOffset(tilePosition);
590     nsIntRegion tileDrawRegion = IntRect(tileOffset, aLayerBuffer.GetScaledTileSize());
591     tileDrawRegion.AndWith(compositeRegion);
592 
593     if (tileDrawRegion.IsEmpty()) {
594       continue;
595     }
596 
597     tileDrawRegion.ScaleRoundOut(resolution, resolution);
598     RenderTile(tile, aEffectChain, aOpacity,
599                aTransform, aSamplingFilter, aClipRect, tileDrawRegion,
600                tileOffset * resolution, aLayerBuffer.GetTileSize(),
601                gfx::Rect(visibleRect.x, visibleRect.y,
602                          visibleRect.width, visibleRect.height));
603     if (tile.mTextureHostOnWhite) {
604       componentAlphaDiagnostic = DiagnosticFlags::COMPONENT_ALPHA;
605     }
606   }
607 
608   gfx::Rect rect(visibleRect.x, visibleRect.y,
609                  visibleRect.width, visibleRect.height);
610   GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTENT | componentAlphaDiagnostic,
611                                    rect, aClipRect, aTransform, mFlashCounter);
612 }
613 
614 void
PrintInfo(std::stringstream & aStream,const char * aPrefix)615 TiledContentHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
616 {
617   aStream << aPrefix;
618   aStream << nsPrintfCString("TiledContentHost (0x%p)", this).get();
619 
620   if (gfxPrefs::LayersDumpTexture() || profiler_feature_active("layersdump")) {
621     nsAutoCString pfx(aPrefix);
622     pfx += "  ";
623 
624     Dump(aStream, pfx.get(), false);
625   }
626 }
627 
628 void
Dump(std::stringstream & aStream,const char * aPrefix,bool aDumpHtml)629 TiledContentHost::Dump(std::stringstream& aStream,
630                        const char* aPrefix,
631                        bool aDumpHtml)
632 {
633   mTiledBuffer.Dump(aStream, aPrefix, aDumpHtml,
634       TextureDumpMode::DoNotCompress /* compression not supported on host side */);
635 }
636 
637 void
AddAnimationInvalidation(nsIntRegion & aRegion)638 TiledContentHost::AddAnimationInvalidation(nsIntRegion& aRegion)
639 {
640   return mTiledBuffer.AddAnimationInvalidation(aRegion);
641 }
642 
643 
644 } // namespace layers
645 } // namespace mozilla
646