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 #ifndef GFX_LayerManagerComposite_H
7 #define GFX_LayerManagerComposite_H
8 
9 #include <stdint.h>                     // for int32_t, uint32_t
10 #include "GLDefs.h"                     // for GLenum
11 #include "Layers.h"
12 #include "Units.h"                      // for ParentLayerIntRect
13 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
14 #include "mozilla/Attributes.h"         // for override
15 #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed
16 #include "mozilla/gfx/2D.h"
17 #include "mozilla/gfx/Point.h"          // for IntSize
18 #include "mozilla/gfx/Rect.h"           // for Rect
19 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
20 #include "mozilla/layers/CompositorTypes.h"
21 #include "mozilla/layers/Effects.h"     // for EffectChain
22 #include "mozilla/layers/LayersMessages.h"
23 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend, etc
24 #include "mozilla/Maybe.h"              // for Maybe
25 #include "mozilla/RefPtr.h"
26 #include "mozilla/UniquePtr.h"
27 #include "nsAString.h"
28 #include "mozilla/RefPtr.h"                   // for nsRefPtr
29 #include "nsCOMPtr.h"                   // for already_AddRefed
30 #include "nsDebug.h"                    // for NS_ASSERTION
31 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
32 #include "nsRect.h"                     // for mozilla::gfx::IntRect
33 #include "nsRegion.h"                   // for nsIntRegion
34 #include "nscore.h"                     // for nsAString, etc
35 #include "LayerTreeInvalidation.h"
36 
37 class gfxContext;
38 
39 #ifdef XP_WIN
40 #include <windows.h>
41 #endif
42 
43 namespace mozilla {
44 namespace gfx {
45 class DrawTarget;
46 } // namespace gfx
47 
48 namespace layers {
49 
50 class CanvasLayerComposite;
51 class ColorLayerComposite;
52 class CompositableHost;
53 class Compositor;
54 class ContainerLayerComposite;
55 struct EffectChain;
56 class ImageLayer;
57 class ImageLayerComposite;
58 class LayerComposite;
59 class RefLayerComposite;
60 class PaintedLayerComposite;
61 class TextRenderer;
62 class CompositingRenderTarget;
63 struct FPSState;
64 class PaintCounter;
65 
66 static const int kVisualWarningDuration = 150; // ms
67 
68 class LayerManagerComposite final : public LayerManager
69 {
70   typedef mozilla::gfx::DrawTarget DrawTarget;
71   typedef mozilla::gfx::IntSize IntSize;
72   typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
73 
74 public:
75   explicit LayerManagerComposite(Compositor* aCompositor);
76   ~LayerManagerComposite();
77 
78   virtual void Destroy() override;
79 
80   /**
81    * Sets the clipping region for this layer manager. This is important on
82    * windows because using OGL we no longer have GDI's native clipping. Therefor
83    * widget must tell us what part of the screen is being invalidated,
84    * and we should clip to this.
85    *
86    * \param aClippingRegion Region to clip to. Setting an empty region
87    * will disable clipping.
88    */
SetClippingRegion(const nsIntRegion & aClippingRegion)89   void SetClippingRegion(const nsIntRegion& aClippingRegion)
90   {
91     mClippingRegion = aClippingRegion;
92   }
93 
94   /**
95    * LayerManager implementation.
96    */
AsLayerManagerComposite()97   virtual LayerManagerComposite* AsLayerManagerComposite() override
98   {
99     return this;
100   }
101 
102   void UpdateRenderBounds(const gfx::IntRect& aRect);
103 
104   virtual bool BeginTransaction() override;
BeginTransactionWithTarget(gfxContext * aTarget)105   virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override
106   {
107     MOZ_CRASH("GFX: Use BeginTransactionWithDrawTarget");
108     return false;
109   }
110   void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
111                                       const gfx::IntRect& aRect);
112 
113   virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override
114   {
115     MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)");
116     return false;
117   }
118   virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
119                               void* aCallbackData,
120                               EndTransactionFlags aFlags = END_DEFAULT) override
121   {
122     MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)");
123   }
124   void EndTransaction(const TimeStamp& aTimeStamp,
125                       EndTransactionFlags aFlags = END_DEFAULT);
126 
SetRoot(Layer * aLayer)127   virtual void SetRoot(Layer* aLayer) override { mRoot = aLayer; }
128 
129   // XXX[nrc]: never called, we should move this logic to ClientLayerManager
130   // (bug 946926).
131   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override;
132 
GetMaxTextureSize()133   virtual int32_t GetMaxTextureSize() const override
134   {
135     MOZ_CRASH("GFX: Call on compositor, not LayerManagerComposite");
136   }
137 
138   virtual void ClearCachedResources(Layer* aSubtree = nullptr) override;
139 
140   virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
141   virtual already_AddRefed<ContainerLayer> CreateContainerLayer() override;
142   virtual already_AddRefed<ImageLayer> CreateImageLayer() override;
143   virtual already_AddRefed<ColorLayer> CreateColorLayer() override;
144   virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
145   already_AddRefed<PaintedLayerComposite> CreatePaintedLayerComposite();
146   already_AddRefed<ContainerLayerComposite> CreateContainerLayerComposite();
147   already_AddRefed<ImageLayerComposite> CreateImageLayerComposite();
148   already_AddRefed<ColorLayerComposite> CreateColorLayerComposite();
149   already_AddRefed<CanvasLayerComposite> CreateCanvasLayerComposite();
150   already_AddRefed<RefLayerComposite> CreateRefLayerComposite();
151 
GetBackendType()152   virtual LayersBackend GetBackendType() override
153   {
154     MOZ_CRASH("GFX: Shouldn't be called for composited layer manager");
155   }
GetBackendName(nsAString & name)156   virtual void GetBackendName(nsAString& name) override
157   {
158     MOZ_CRASH("GFX: Shouldn't be called for composited layer manager");
159   }
160 
161   virtual bool AreComponentAlphaLayersEnabled() override;
162 
163   virtual already_AddRefed<DrawTarget>
164     CreateOptimalMaskDrawTarget(const IntSize &aSize) override;
165 
Name()166   virtual const char* Name() const override { return ""; }
167 
168   /**
169    * Post-processes layers before composition. This performs the following:
170    *
171    *   - Applies occlusion culling. This restricts the shadow visible region
172    *     of layers that are covered with opaque content.
173    *     |aOpaqueRegion| is the region already known to be covered with opaque
174    *     content, in the post-transform coordinate space of aLayer.
175    *
176    *   - Recomputes visible regions to account for async transforms.
177    *     Each layer accumulates into |aVisibleRegion| its post-transform
178    *     (including async transforms) visible region.
179    */
180   void PostProcessLayers(Layer* aLayer,
181                          nsIntRegion& aOpaqueRegion,
182                          LayerIntRegion& aVisibleRegion,
183                          const Maybe<ParentLayerIntRect>& aClipFromAncestors);
184 
185   /**
186    * RAII helper class to add a mask effect with the compositable from aMaskLayer
187    * to the EffectChain aEffect and notify the compositable when we are done.
188    */
189   class AutoAddMaskEffect
190   {
191   public:
192     AutoAddMaskEffect(Layer* aMaskLayer,
193                       EffectChain& aEffect);
194     ~AutoAddMaskEffect();
195 
Failed()196     bool Failed() const { return mFailed; }
197   private:
198     CompositableHost* mCompositable;
199     bool mFailed;
200   };
201 
202   /**
203    * returns true if PlatformAllocBuffer will return a buffer that supports
204    * direct texturing
205    */
206   static bool SupportsDirectTexturing();
207 
208   static void PlatformSyncBeforeReplyUpdate();
209 
AddInvalidRegion(const nsIntRegion & aRegion)210   void AddInvalidRegion(const nsIntRegion& aRegion)
211   {
212     mInvalidRegion.Or(mInvalidRegion, aRegion);
213   }
214 
ClearApproximatelyVisibleRegions(uint64_t aLayersId,const Maybe<uint32_t> & aPresShellId)215   void ClearApproximatelyVisibleRegions(uint64_t aLayersId,
216                                         const Maybe<uint32_t>& aPresShellId)
217   {
218     for (auto iter = mVisibleRegions.Iter(); !iter.Done(); iter.Next()) {
219       if (iter.Key().mLayersId == aLayersId &&
220           (!aPresShellId || iter.Key().mPresShellId == *aPresShellId)) {
221         iter.Remove();
222       }
223     }
224   }
225 
UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid & aGuid,const CSSIntRegion & aRegion)226   void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
227                                         const CSSIntRegion& aRegion)
228   {
229     CSSIntRegion* regionForScrollFrame = mVisibleRegions.LookupOrAdd(aGuid);
230     MOZ_ASSERT(regionForScrollFrame);
231 
232     *regionForScrollFrame = aRegion;
233   }
234 
GetApproximatelyVisibleRegion(const ScrollableLayerGuid & aGuid)235   CSSIntRegion* GetApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid)
236   {
237     return mVisibleRegions.Get(aGuid);
238   }
239 
GetCompositor()240   Compositor* GetCompositor() const
241   {
242     return mCompositor;
243   }
244 
245   // Called by CompositorBridgeParent when a new compositor has been created due
246   // to a device reset. The layer manager must clear any cached resources
247   // attached to the old compositor, and make a best effort at ignoring
248   // layer or texture updates against the old compositor.
249   void ChangeCompositor(Compositor* aNewCompositor);
250 
251   /**
252    * LayerManagerComposite provides sophisticated debug overlays
253    * that can request a next frame.
254    */
DebugOverlayWantsNextFrame()255   bool DebugOverlayWantsNextFrame() { return mDebugOverlayWantsNextFrame; }
SetDebugOverlayWantsNextFrame(bool aVal)256   void SetDebugOverlayWantsNextFrame(bool aVal)
257   { mDebugOverlayWantsNextFrame = aVal; }
258 
259   void NotifyShadowTreeTransaction();
260 
GetTextRenderer()261   TextRenderer* GetTextRenderer() { return mTextRenderer; }
262 
263   /**
264    * Add an on frame warning.
265    * @param severity ranges from 0 to 1. It's used to compute the warning color.
266    */
VisualFrameWarning(float severity)267   void VisualFrameWarning(float severity) {
268     mozilla::TimeStamp now = TimeStamp::Now();
269     if (mWarnTime.IsNull() ||
270         severity > mWarningLevel ||
271         mWarnTime + TimeDuration::FromMilliseconds(kVisualWarningDuration) < now) {
272       mWarnTime = now;
273       mWarningLevel = severity;
274     }
275   }
276 
UnusedApzTransformWarning()277   void UnusedApzTransformWarning() {
278     mUnusedApzTransformWarning = true;
279   }
DisabledApzWarning()280   void DisabledApzWarning() {
281     mDisabledApzWarning = true;
282   }
283 
LastFrameMissedHWC()284   bool LastFrameMissedHWC() { return mLastFrameMissedHWC; }
285 
286   bool AsyncPanZoomEnabled() const override;
287 
AppendImageCompositeNotification(const ImageCompositeNotification & aNotification)288   void AppendImageCompositeNotification(const ImageCompositeNotification& aNotification)
289   {
290     // Only send composite notifications when we're drawing to the screen,
291     // because that's what they mean.
292     // Also when we're not drawing to the screen, DidComposite will not be
293     // called to extract and send these notifications, so they might linger
294     // and contain stale ImageContainerParent pointers.
295     if (!mCompositor->GetTargetContext()) {
296       mImageCompositeNotifications.AppendElement(aNotification);
297     }
298   }
ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotification> * aNotifications)299   void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotification>* aNotifications)
300   {
301     aNotifications->AppendElements(Move(mImageCompositeNotifications));
302   }
303 
304   // Indicate that we need to composite even if nothing in our layers has
305   // changed, so that the widget can draw something different in its window
306   // overlay.
SetWindowOverlayChanged()307   void SetWindowOverlayChanged() { mWindowOverlayChanged = true; }
308 
ForcePresent()309   void ForcePresent() { mCompositor->ForcePresent(); }
310 
SetPaintTime(const TimeDuration & aPaintTime)311   void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; }
312 
313 private:
314   /** Region we're clipping our current drawing to. */
315   nsIntRegion mClippingRegion;
316   gfx::IntRect mRenderBounds;
317 
318   /** Current root layer. */
319   LayerComposite* RootLayer() const;
320 
321   /**
322    * Update the invalid region and render it.
323    */
324   void UpdateAndRender();
325 
326   /**
327    * Render the current layer tree to the active target.
328    */
329   void Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion);
330 #if defined(MOZ_WIDGET_ANDROID)
331   void RenderToPresentationSurface();
332 #endif
333 
334   /**
335    * We need to know our invalid region before we're ready to render.
336    */
337   void InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const gfx::IntRect& aBounds);
338 
339   /**
340    * Render debug overlays such as the FPS/FrameCounter above the frame.
341    */
342   void RenderDebugOverlay(const gfx::IntRect& aBounds);
343 
344 
345   RefPtr<CompositingRenderTarget> PushGroupForLayerEffects();
346   void PopGroupForLayerEffects(RefPtr<CompositingRenderTarget> aPreviousTarget,
347                                gfx::IntRect aClipRect,
348                                bool aGrayscaleEffect,
349                                bool aInvertEffect,
350                                float aContrastEffect);
351 
352   void ChangeCompositorInternal(Compositor* aNewCompositor);
353 
354   float mWarningLevel;
355   mozilla::TimeStamp mWarnTime;
356   bool mUnusedApzTransformWarning;
357   bool mDisabledApzWarning;
358   RefPtr<Compositor> mCompositor;
359   UniquePtr<LayerProperties> mClonedLayerTreeProperties;
360 
361   nsTArray<ImageCompositeNotification> mImageCompositeNotifications;
362 
363   /**
364    * Context target, nullptr when drawing directly to our swap chain.
365    */
366   RefPtr<gfx::DrawTarget> mTarget;
367   gfx::IntRect mTargetBounds;
368 
369   nsIntRegion mInvalidRegion;
370 
371   typedef nsClassHashtable<nsGenericHashKey<ScrollableLayerGuid>,
372                            CSSIntRegion> VisibleRegions;
373   VisibleRegions mVisibleRegions;
374 
375   UniquePtr<FPSState> mFPS;
376 
377   bool mInTransaction;
378   bool mIsCompositorReady;
379   bool mDebugOverlayWantsNextFrame;
380 
381   RefPtr<CompositingRenderTarget> mTwoPassTmpTarget;
382   RefPtr<TextRenderer> mTextRenderer;
383   bool mGeometryChanged;
384 
385   // Testing property. If hardware composer is supported, this will return
386   // true if the last frame was deemed 'too complicated' to be rendered.
387   bool mLastFrameMissedHWC;
388 
389   bool mWindowOverlayChanged;
390   TimeDuration mLastPaintTime;
391   TimeStamp mRenderStartTime;
392 
393 #ifdef USE_SKIA
394   /**
395    * Render paint and composite times above the frame.
396    */
397   void DrawPaintTimes(Compositor* aCompositor);
398   RefPtr<PaintCounter> mPaintCounter;
399 #endif
400 };
401 
402 /**
403  * Composite layers are for use with OMTC on the compositor thread only. There
404  * must be corresponding Basic layers on the content thread. For composite
405  * layers, the layer manager only maintains the layer tree, all rendering is
406  * done by a Compositor (see Compositor.h). As such, composite layers are
407  * platform-independent and can be used on any platform for which there is a
408  * Compositor implementation.
409  *
410  * The composite layer tree reflects exactly the basic layer tree. To
411  * composite to screen, the layer manager walks the layer tree calling render
412  * methods which in turn call into their CompositableHosts' Composite methods.
413  * These call Compositor::DrawQuad to do the rendering.
414  *
415  * Mostly, layers are updated during the layers transaction. This is done from
416  * CompositableClient to CompositableHost without interacting with the layer.
417  *
418  * A reference to the Compositor is stored in LayerManagerComposite.
419  */
420 class LayerComposite
421 {
422 public:
423   explicit LayerComposite(LayerManagerComposite* aManager);
424 
425   virtual ~LayerComposite();
426 
GetFirstChildComposite()427   virtual LayerComposite* GetFirstChildComposite()
428   {
429     return nullptr;
430   }
431 
432   /* Do NOT call this from the generic LayerComposite destructor.  Only from the
433    * concrete class destructor
434    */
435   virtual void Destroy();
436 
437   virtual Layer* GetLayer() = 0;
438 
439   virtual void SetLayerManager(LayerManagerComposite* aManager);
440 
GetLayerManager()441   LayerManagerComposite* GetLayerManager() const { return mCompositeManager; }
442 
443   /**
444    * Perform a first pass over the layer tree to render all of the intermediate
445    * surfaces that we can. This allows us to avoid framebuffer switches in the
446    * middle of our render which is inefficient especially on mobile GPUs. This
447    * must be called before RenderLayer.
448    */
Prepare(const RenderTargetIntRect & aClipRect)449   virtual void Prepare(const RenderTargetIntRect& aClipRect) {}
450 
451   // TODO: This should also take RenderTargetIntRect like Prepare.
452   virtual void RenderLayer(const gfx::IntRect& aClipRect) = 0;
453 
SetCompositableHost(CompositableHost *)454   virtual bool SetCompositableHost(CompositableHost*)
455   {
456     // We must handle this gracefully, see bug 967824
457     NS_WARNING("called SetCompositableHost for a layer type not accepting a compositable");
458     return false;
459   }
460   virtual CompositableHost* GetCompositableHost() = 0;
461 
462   virtual void CleanupResources() = 0;
463 
DestroyFrontBuffer()464   virtual void DestroyFrontBuffer() { }
465 
466   void AddBlendModeEffect(EffectChain& aEffectChain);
467 
GenEffectChain(EffectChain & aEffect)468   virtual void GenEffectChain(EffectChain& aEffect) { }
469 
470   /**
471    * The following methods are
472    *
473    * CONSTRUCTION PHASE ONLY
474    *
475    * They are analogous to the Layer interface.
476    */
SetShadowVisibleRegion(const LayerIntRegion & aRegion)477   void SetShadowVisibleRegion(const LayerIntRegion& aRegion)
478   {
479     mShadowVisibleRegion = aRegion;
480   }
481 
SetShadowOpacity(float aOpacity)482   void SetShadowOpacity(float aOpacity)
483   {
484     mShadowOpacity = aOpacity;
485   }
SetShadowOpacitySetByAnimation(bool aSetByAnimation)486   void SetShadowOpacitySetByAnimation(bool aSetByAnimation)
487   {
488     mShadowOpacitySetByAnimation = aSetByAnimation;
489   }
490 
SetShadowClipRect(const Maybe<ParentLayerIntRect> & aRect)491   void SetShadowClipRect(const Maybe<ParentLayerIntRect>& aRect)
492   {
493     mShadowClipRect = aRect;
494   }
495 
SetShadowBaseTransform(const gfx::Matrix4x4 & aMatrix)496   void SetShadowBaseTransform(const gfx::Matrix4x4& aMatrix)
497   {
498     mShadowTransform = aMatrix;
499   }
SetShadowTransformSetByAnimation(bool aSetByAnimation)500   void SetShadowTransformSetByAnimation(bool aSetByAnimation)
501   {
502     mShadowTransformSetByAnimation = aSetByAnimation;
503   }
504 
SetLayerComposited(bool value)505   void SetLayerComposited(bool value)
506   {
507     mLayerComposited = value;
508   }
509 
SetClearRect(const gfx::IntRect & aRect)510   void SetClearRect(const gfx::IntRect& aRect)
511   {
512     mClearRect = aRect;
513   }
514 
515   // These getters can be used anytime.
GetShadowOpacity()516   float GetShadowOpacity() { return mShadowOpacity; }
GetShadowClipRect()517   const Maybe<ParentLayerIntRect>& GetShadowClipRect() { return mShadowClipRect; }
GetShadowVisibleRegion()518   const LayerIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
GetShadowBaseTransform()519   const gfx::Matrix4x4& GetShadowBaseTransform() { return mShadowTransform; }
520   gfx::Matrix4x4 GetShadowTransform();
GetShadowTransformSetByAnimation()521   bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
GetShadowOpacitySetByAnimation()522   bool GetShadowOpacitySetByAnimation() { return mShadowOpacitySetByAnimation; }
HasLayerBeenComposited()523   bool HasLayerBeenComposited() { return mLayerComposited; }
GetClearRect()524   gfx::IntRect GetClearRect() { return mClearRect; }
525 
526   // Returns false if the layer is attached to an older compositor.
527   bool HasStaleCompositor() const;
528 
529   /**
530    * Return the part of the visible region that has been fully rendered.
531    * While progressive drawing is in progress this region will be
532    * a subset of the shadow visible region.
533    */
534   virtual nsIntRegion GetFullyRenderedRegion();
535 
536   /**
537    * Return true if a checkerboarding background color needs to be drawn
538    * for this layer.
539    */
540   bool NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor = nullptr);
541 
542 protected:
543   gfx::Matrix4x4 mShadowTransform;
544   LayerIntRegion mShadowVisibleRegion;
545   Maybe<ParentLayerIntRect> mShadowClipRect;
546   LayerManagerComposite* mCompositeManager;
547   RefPtr<Compositor> mCompositor;
548   float mShadowOpacity;
549   bool mShadowTransformSetByAnimation;
550   bool mShadowOpacitySetByAnimation;
551   bool mDestroyed;
552   bool mLayerComposited;
553   gfx::IntRect mClearRect;
554 };
555 
556 // Render aLayer using aCompositor and apply all mask layers of aLayer: The
557 // layer's own mask layer (aLayer->GetMaskLayer()), and any ancestor mask
558 // layers.
559 // If more than one mask layer needs to be applied, we use intermediate surfaces
560 // (CompositingRenderTargets) for rendering, applying one mask layer at a time.
561 // Callers need to provide a callback function aRenderCallback that does the
562 // actual rendering of the source. It needs to have the following form:
563 // void (EffectChain& effectChain, const Rect& clipRect)
564 // aRenderCallback is called exactly once, inside this function, unless aLayer's
565 // visible region is completely clipped out (in that case, aRenderCallback won't
566 // be called at all).
567 // This function calls aLayer->AsLayerComposite()->AddBlendModeEffect for the
568 // final rendering pass.
569 //
570 // (This function should really live in LayerManagerComposite.cpp, but we
571 // need to use templates for passing lambdas until bug 1164522 is resolved.)
572 template<typename RenderCallbackType>
573 void
RenderWithAllMasks(Layer * aLayer,Compositor * aCompositor,const gfx::IntRect & aClipRect,RenderCallbackType aRenderCallback)574 RenderWithAllMasks(Layer* aLayer, Compositor* aCompositor,
575                    const gfx::IntRect& aClipRect,
576                    RenderCallbackType aRenderCallback)
577 {
578   Layer* firstMask = nullptr;
579   size_t maskLayerCount = 0;
580   size_t nextAncestorMaskLayer = 0;
581 
582   size_t ancestorMaskLayerCount = aLayer->GetAncestorMaskLayerCount();
583   if (Layer* ownMask = aLayer->GetMaskLayer()) {
584     firstMask = ownMask;
585     maskLayerCount = ancestorMaskLayerCount + 1;
586     nextAncestorMaskLayer = 0;
587   } else if (ancestorMaskLayerCount > 0) {
588     firstMask = aLayer->GetAncestorMaskLayerAt(0);
589     maskLayerCount = ancestorMaskLayerCount;
590     nextAncestorMaskLayer = 1;
591   } else {
592     // no mask layers at all
593   }
594 
595   if (maskLayerCount <= 1) {
596     // This is the common case. Render in one pass and return.
597     EffectChain effectChain(aLayer);
598     LayerManagerComposite::AutoAddMaskEffect
599       autoMaskEffect(firstMask, effectChain);
600     aLayer->AsLayerComposite()->AddBlendModeEffect(effectChain);
601     aRenderCallback(effectChain, aClipRect);
602     return;
603   }
604 
605   // We have multiple mask layers.
606   // We split our list of mask layers into three parts:
607   //  (1) The first mask
608   //  (2) The list of intermediate masks (every mask except first and last)
609   //  (3) The final mask.
610   // Part (2) can be empty.
611   // For parts (1) and (2) we need to allocate intermediate surfaces to render
612   // into. The final mask gets rendered into the original render target.
613 
614   // Calculate the size of the intermediate surfaces.
615   gfx::Rect visibleRect(aLayer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
616   gfx::Matrix4x4 transform = aLayer->GetEffectiveTransform();
617   // TODO: Use RenderTargetIntRect and TransformBy here
618   gfx::IntRect surfaceRect =
619     RoundedOut(transform.TransformAndClipBounds(visibleRect, gfx::Rect(aClipRect)));
620   if (surfaceRect.IsEmpty()) {
621     return;
622   }
623 
624   RefPtr<CompositingRenderTarget> originalTarget =
625     aCompositor->GetCurrentRenderTarget();
626 
627   RefPtr<CompositingRenderTarget> firstTarget =
628     aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
629   if (!firstTarget) {
630     return;
631   }
632 
633   // Render the source while applying the first mask.
634   aCompositor->SetRenderTarget(firstTarget);
635   {
636     EffectChain firstEffectChain(aLayer);
637     LayerManagerComposite::AutoAddMaskEffect
638       firstMaskEffect(firstMask, firstEffectChain);
639     aRenderCallback(firstEffectChain, aClipRect - surfaceRect.TopLeft());
640     // firstTarget now contains the transformed source with the first mask and
641     // opacity already applied.
642   }
643 
644   // Apply the intermediate masks.
645   gfx::IntRect intermediateClip(surfaceRect - surfaceRect.TopLeft());
646   RefPtr<CompositingRenderTarget> previousTarget = firstTarget;
647   for (size_t i = nextAncestorMaskLayer; i < ancestorMaskLayerCount - 1; i++) {
648     Layer* intermediateMask = aLayer->GetAncestorMaskLayerAt(i);
649     RefPtr<CompositingRenderTarget> intermediateTarget =
650       aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
651     if (!intermediateTarget) {
652       break;
653     }
654     aCompositor->SetRenderTarget(intermediateTarget);
655     EffectChain intermediateEffectChain(aLayer);
656     LayerManagerComposite::AutoAddMaskEffect
657       intermediateMaskEffect(intermediateMask, intermediateEffectChain);
658     if (intermediateMaskEffect.Failed()) {
659       continue;
660     }
661     intermediateEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
662     aCompositor->DrawQuad(gfx::Rect(surfaceRect), intermediateClip,
663                           intermediateEffectChain, 1.0, gfx::Matrix4x4());
664     previousTarget = intermediateTarget;
665   }
666 
667   aCompositor->SetRenderTarget(originalTarget);
668 
669   // Apply the final mask, rendering into originalTarget.
670   EffectChain finalEffectChain(aLayer);
671   finalEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
672   Layer* finalMask = aLayer->GetAncestorMaskLayerAt(ancestorMaskLayerCount - 1);
673 
674   // The blend mode needs to be applied in this final step, because this is
675   // where we're blending with the actual background (which is in originalTarget).
676   aLayer->AsLayerComposite()->AddBlendModeEffect(finalEffectChain);
677   LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(finalMask, finalEffectChain);
678   if (!autoMaskEffect.Failed()) {
679     aCompositor->DrawQuad(gfx::Rect(surfaceRect), aClipRect,
680                           finalEffectChain, 1.0, gfx::Matrix4x4());
681   }
682 }
683 
684 } // namespace layers
685 } // namespace mozilla
686 
687 #endif /* GFX_LayerManagerComposite_H */
688