LCOV - code coverage report
Current view: top level - gfx/layers/ipc - ShadowLayers.h (source / functions) Hit Total Coverage
Test: output.info Lines: 20 35 57.1 %
Date: 2017-07-14 16:53:18 Functions: 14 26 53.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * vim: sw=2 ts=8 et :
       3             :  */
       4             : /* This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       7             : 
       8             : #ifndef mozilla_layers_ShadowLayers_h
       9             : #define mozilla_layers_ShadowLayers_h 1
      10             : 
      11             : #include <stddef.h>                     // for size_t
      12             : #include <stdint.h>                     // for uint64_t
      13             : #include "gfxTypes.h"
      14             : #include "mozilla/Attributes.h"         // for override
      15             : #include "mozilla/gfx/Rect.h"
      16             : #include "mozilla/WidgetUtils.h"        // for ScreenRotation
      17             : #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
      18             : #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
      19             : #include "mozilla/layers/CompositableForwarder.h"
      20             : #include "mozilla/layers/FocusTarget.h"
      21             : #include "mozilla/layers/LayersTypes.h"
      22             : #include "mozilla/layers/TextureForwarder.h"
      23             : #include "mozilla/layers/CompositorTypes.h"  // for OpenMode, etc
      24             : #include "mozilla/layers/CompositorBridgeChild.h"
      25             : #include "nsCOMPtr.h"                   // for already_AddRefed
      26             : #include "nsRegion.h"                   // for nsIntRegion
      27             : #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
      28             : #include "nsIWidget.h"
      29             : #include <vector>
      30             : #include "nsExpirationTracker.h"
      31             : 
      32             : namespace mozilla {
      33             : namespace layers {
      34             : 
      35             : class ClientLayerManager;
      36             : class CompositorBridgeChild;
      37             : class FixedSizeSmallShmemSectionAllocator;
      38             : class ImageContainer;
      39             : class Layer;
      40             : class PLayerTransactionChild;
      41             : class LayerTransactionChild;
      42             : class ShadowableLayer;
      43             : class SurfaceDescriptor;
      44             : class TextureClient;
      45             : class ThebesBuffer;
      46             : class ThebesBufferData;
      47             : class Transaction;
      48             : 
      49             : /**
      50             :  * See ActiveResourceTracker below.
      51             :  */
      52           0 : class ActiveResource
      53             : {
      54             : public:
      55             :  virtual void NotifyInactive() = 0;
      56           0 :   nsExpirationState* GetExpirationState() { return &mExpirationState; }
      57           0 :   bool IsActivityTracked() { return mExpirationState.IsTracked(); }
      58             : private:
      59             :   nsExpirationState mExpirationState;
      60             : };
      61             : 
      62             : /**
      63             :  * A convenience class on top of nsExpirationTracker
      64             :  */
      65           0 : class ActiveResourceTracker : public nsExpirationTracker<ActiveResource, 3>
      66             : {
      67             : public:
      68           2 :   ActiveResourceTracker(uint32_t aExpirationCycle, const char* aName,
      69             :                         nsIEventTarget* aEventTarget)
      70           2 :   : nsExpirationTracker(aExpirationCycle, aName, aEventTarget)
      71           2 :   {}
      72             : 
      73           0 :   virtual void NotifyExpired(ActiveResource* aResource) override
      74             :   {
      75           0 :     RemoveObject(aResource);
      76           0 :     aResource->NotifyInactive();
      77           0 :   }
      78             : };
      79             : 
      80             : /**
      81             :  * We want to share layer trees across thread contexts and address
      82             :  * spaces for several reasons; chief among them
      83             :  *
      84             :  *  - a parent process can paint a child process's layer tree while
      85             :  *    the child process is blocked, say on content script.  This is
      86             :  *    important on mobile devices where UI responsiveness is key.
      87             :  *
      88             :  *  - a dedicated "compositor" process can asynchronously (wrt the
      89             :  *    browser process) composite and animate layer trees, allowing a
      90             :  *    form of pipeline parallelism between compositor/browser/content
      91             :  *
      92             :  *  - a dedicated "compositor" process can take all responsibility for
      93             :  *    accessing the GPU, which is desirable on systems with
      94             :  *    buggy/leaky drivers because the compositor process can die while
      95             :  *    browser and content live on (and failover mechanisms can be
      96             :  *    installed to quickly bring up a replacement compositor)
      97             :  *
      98             :  * The Layers model has a crisply defined API, which makes it easy to
      99             :  * safely "share" layer trees.  The ShadowLayers API extends Layers to
     100             :  * allow a remote, parent process to access a child process's layer
     101             :  * tree.
     102             :  *
     103             :  * ShadowLayerForwarder publishes a child context's layer tree to a
     104             :  * parent context.  This comprises recording layer-tree modifications
     105             :  * into atomic transactions and pushing them over IPC.
     106             :  *
     107             :  * LayerManagerComposite grafts layer subtrees published by child-context
     108             :  * ShadowLayerForwarder(s) into a parent-context layer tree.
     109             :  *
     110             :  * (Advanced note: because our process tree may have a height >2, a
     111             :  * non-leaf subprocess may both receive updates from child processes
     112             :  * and publish them to parent processes.  Put another way,
     113             :  * LayerManagers may be both LayerManagerComposites and
     114             :  * ShadowLayerForwarders.)
     115             :  *
     116             :  * There are only shadow types for layers that have different shadow
     117             :  * vs. not-shadow behavior.  ColorLayers and ContainerLayers behave
     118             :  * the same way in both regimes (so far).
     119             :  *
     120             :  *
     121             :  * The mecanism to shadow the layer tree on the compositor through IPC works as
     122             :  * follows:
     123             :  * The layer tree is managed on the content thread, and shadowed in the compositor
     124             :  * thread. The shadow layer tree is only kept in sync with whatever happens in
     125             :  * the content thread. To do this we use IPDL protocols. IPDL is a domain
     126             :  * specific language that describes how two processes or thread should
     127             :  * communicate. C++ code is generated from .ipdl files to implement the message
     128             :  * passing, synchronization and serialization logic. To use the generated code
     129             :  * we implement classes that inherit the generated IPDL actor. the ipdl actors
     130             :  * of a protocol PX are PXChild or PXParent (the generated class), and we
     131             :  * conventionally implement XChild and XParent. The Parent side of the protocol
     132             :  * is the one that lives on the compositor thread. Think of IPDL actors as
     133             :  * endpoints of communication. they are useful to send messages and also to
     134             :  * dispatch the message to the right actor on the other side. One nice property
     135             :  * of an IPDL actor is that when an actor, say PXChild is sent in a message, the
     136             :  * PXParent comes out in the other side. we use this property a lot to dispatch
     137             :  * messages to the right layers and compositable, each of which have their own
     138             :  * ipdl actor on both side.
     139             :  *
     140             :  * Most of the synchronization logic happens in layer transactions and
     141             :  * compositable transactions.
     142             :  * A transaction is a set of changes to the layers and/or the compositables
     143             :  * that are sent and applied together to the compositor thread to keep the
     144             :  * LayerComposite in a coherent state.
     145             :  * Layer transactions maintain the shape of the shadow layer tree, and
     146             :  * synchronize the texture data held by compositables. Layer transactions
     147             :  * are always between the content thread and the compositor thread.
     148             :  * Compositable transactions are subset of a layer transaction with which only
     149             :  * compositables and textures can be manipulated, and does not always originate
     150             :  * from the content thread. (See CompositableForwarder.h and ImageBridgeChild.h)
     151             :  */
     152             : 
     153             : class ShadowLayerForwarder final : public LayersIPCActor
     154             :                                  , public CompositableForwarder
     155             :                                  , public LegacySurfaceDescriptorAllocator
     156             : {
     157             :   friend class ClientLayerManager;
     158             : 
     159             : public:
     160         112 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ShadowLayerForwarder, override);
     161             : 
     162             :   /**
     163             :    * Setup the IPDL actor for aCompositable to be part of layers
     164             :    * transactions.
     165             :    */
     166             :   void Connect(CompositableClient* aCompositable,
     167             :                ImageContainer* aImageContainer) override;
     168             : 
     169             :   /**
     170             :    * Adds an edit in the layers transaction in order to attach
     171             :    * the corresponding compositable and layer on the compositor side.
     172             :    * Connect must have been called on aCompositable beforehand.
     173             :    */
     174             :   void Attach(CompositableClient* aCompositable,
     175             :               ShadowableLayer* aLayer);
     176             : 
     177             :   /**
     178             :    * Adds an edit in the transaction in order to attach a Compositable that
     179             :    * is not managed by this ShadowLayerForwarder (for example, by ImageBridge
     180             :    * in the case of async-video).
     181             :    * Since the compositable is not managed by this forwarder, we can't use
     182             :    * the compositable or it's IPDL actor here, so we use an ID instead, that
     183             :    * is matched on the compositor side.
     184             :    */
     185             :   void AttachAsyncCompositable(const CompositableHandle& aHandle,
     186             :                                ShadowableLayer* aLayer);
     187             : 
     188             :   /**
     189             :    * Begin recording a transaction to be forwarded atomically to a
     190             :    * LayerManagerComposite.
     191             :    */
     192             :   void BeginTransaction(const gfx::IntRect& aTargetBounds,
     193             :                         ScreenRotation aRotation,
     194             :                         mozilla::dom::ScreenOrientationInternal aOrientation);
     195             : 
     196             :   /**
     197             :    * The following methods may only be called after BeginTransaction()
     198             :    * but before EndTransaction().  They mirror the LayerManager
     199             :    * interface in Layers.h.
     200             :    */
     201             : 
     202             :   /**
     203             :    * Notify the shadow manager that a new, "real" layer has been
     204             :    * created, and a corresponding shadow layer should be created in
     205             :    * the compositing process.
     206             :    */
     207             :   void CreatedPaintedLayer(ShadowableLayer* aThebes);
     208             :   void CreatedContainerLayer(ShadowableLayer* aContainer);
     209             :   void CreatedImageLayer(ShadowableLayer* aImage);
     210             :   void CreatedColorLayer(ShadowableLayer* aColor);
     211             :   void CreatedCanvasLayer(ShadowableLayer* aCanvas);
     212             :   void CreatedRefLayer(ShadowableLayer* aRef);
     213             :   void CreatedTextLayer(ShadowableLayer* aRef);
     214             :   void CreatedBorderLayer(ShadowableLayer* aRef);
     215             : 
     216             :   /**
     217             :    * At least one attribute of |aMutant| has changed, and |aMutant|
     218             :    * needs to sync to its shadow layer.  This initial implementation
     219             :    * forwards all attributes when any of the appropriate attribute
     220             :    * set is mutated.
     221             :    */
     222             :   void Mutated(ShadowableLayer* aMutant);
     223             :   void MutatedSimple(ShadowableLayer* aMutant);
     224             : 
     225             :   void SetRoot(ShadowableLayer* aRoot);
     226             :   /**
     227             :    * Insert |aChild| after |aAfter| in |aContainer|.  |aAfter| can be
     228             :    * nullptr to indicated that |aChild| should be appended to the end of
     229             :    * |aContainer|'s child list.
     230             :    */
     231             :   void InsertAfter(ShadowableLayer* aContainer,
     232             :                    ShadowableLayer* aChild,
     233             :                    ShadowableLayer* aAfter = nullptr);
     234             :   void RemoveChild(ShadowableLayer* aContainer,
     235             :                    ShadowableLayer* aChild);
     236             :   void RepositionChild(ShadowableLayer* aContainer,
     237             :                        ShadowableLayer* aChild,
     238             :                        ShadowableLayer* aAfter = nullptr);
     239             : 
     240             :   /**
     241             :    * Set aMaskLayer as the mask on aLayer.
     242             :    * Note that only image layers are properly supported
     243             :    * LayerTransactionParent::UpdateMask and accompanying ipdl
     244             :    * will need changing to update properties for other kinds
     245             :    * of mask layer.
     246             :    */
     247             :   void SetMask(ShadowableLayer* aLayer,
     248             :                ShadowableLayer* aMaskLayer);
     249             : 
     250             :   /**
     251             :    * See CompositableForwarder::UseTiledLayerBuffer
     252             :    */
     253             :   void UseTiledLayerBuffer(CompositableClient* aCompositable,
     254             :                                    const SurfaceDescriptorTiles& aTileLayerDescriptor) override;
     255             : 
     256             :   void ReleaseCompositable(const CompositableHandle& aHandle) override;
     257             :   bool DestroyInTransaction(PTextureChild* aTexture) override;
     258             :   bool DestroyInTransaction(const CompositableHandle& aHandle);
     259             : 
     260             :   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
     261             :                                              TextureClient* aTexture) override;
     262             : 
     263             :   /**
     264             :    * Communicate to the compositor that aRegion in the texture identified by aLayer
     265             :    * and aIdentifier has been updated to aThebesBuffer.
     266             :    */
     267             :   virtual void UpdateTextureRegion(CompositableClient* aCompositable,
     268             :                                    const ThebesBufferData& aThebesBufferData,
     269             :                                    const nsIntRegion& aUpdatedRegion) override;
     270             : 
     271             :   /**
     272             :    * See CompositableForwarder::UseTextures
     273             :    */
     274             :   virtual void UseTextures(CompositableClient* aCompositable,
     275             :                            const nsTArray<TimedTextureClient>& aTextures) override;
     276             :   virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
     277             :                                          TextureClient* aClientOnBlack,
     278             :                                          TextureClient* aClientOnWhite) override;
     279             : 
     280             :   /**
     281             :    * Used for debugging to tell the compositor how long this frame took to paint.
     282             :    */
     283             :   void SendPaintTime(uint64_t aId, TimeDuration aPaintTime);
     284             : 
     285             :   /**
     286             :    * End the current transaction and forward it to LayerManagerComposite.
     287             :    * |aReplies| are directions from the LayerManagerComposite to the
     288             :    * caller of EndTransaction().
     289             :    */
     290             :   bool EndTransaction(const nsIntRegion& aRegionToClear,
     291             :                       uint64_t aId,
     292             :                       bool aScheduleComposite,
     293             :                       uint32_t aPaintSequenceNumber,
     294             :                       bool aIsRepeatTransaction,
     295             :                       const mozilla::TimeStamp& aTransactionStart,
     296             :                       bool* aSent);
     297             : 
     298             :   /**
     299             :    * Set an actor through which layer updates will be pushed.
     300             :    */
     301             :   void SetShadowManager(PLayerTransactionChild* aShadowManager);
     302             : 
     303             :   /**
     304             :    * Layout calls here to cache current plugin widget configuration
     305             :    * data. We ship this across with the rest of the layer updates when
     306             :    * we update. Chrome handles applying these changes.
     307             :    */
     308             :   void StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>&
     309             :                                        aConfigurations);
     310             : 
     311             :   void StopReceiveAsyncParentMessge();
     312             : 
     313             :   void ClearCachedResources();
     314             : 
     315             :   void Composite();
     316             : 
     317             :   /**
     318             :    * True if this is forwarding to a LayerManagerComposite.
     319             :    */
     320         829 :   bool HasShadowManager() const { return !!mShadowManager; }
     321           0 :   LayerTransactionChild* GetShadowManager() const { return mShadowManager.get(); }
     322             : 
     323             :   // Send a synchronous message asking the LayerTransactionParent in the
     324             :   // compositor to shutdown.
     325             :   void SynchronouslyShutdown();
     326             : 
     327           0 :   virtual void WindowOverlayChanged() { mWindowOverlayChanged = true; }
     328             : 
     329             :   /**
     330             :    * The following Alloc/Open/Destroy interfaces abstract over the
     331             :    * details of working with surfaces that are shared across
     332             :    * processes.  They provide the glue between C++ Layers and the
     333             :    * LayerComposite IPC system.
     334             :    *
     335             :    * The basic lifecycle is
     336             :    *
     337             :    *  - a Layer needs a buffer.  Its ShadowableLayer subclass calls
     338             :    *    AllocBuffer(), then calls one of the Created*Buffer() methods
     339             :    *    above to transfer the (temporary) front buffer to its
     340             :    *    LayerComposite in the other process.  The Layer needs a
     341             :    *    gfxASurface to paint, so the ShadowableLayer uses
     342             :    *    OpenDescriptor(backBuffer) to get that surface, and hands it
     343             :    *    out to the Layer.
     344             :    *
     345             :    * - a Layer has painted new pixels.  Its ShadowableLayer calls one
     346             :    *   of the Painted*Buffer() methods above with the back buffer
     347             :    *   descriptor.  This notification is forwarded to the LayerComposite,
     348             :    *   which uses OpenDescriptor() to access the newly-painted pixels.
     349             :    *   The LayerComposite then updates its front buffer in a Layer- and
     350             :    *   platform-dependent way, and sends a surface descriptor back to
     351             :    *   the ShadowableLayer that becomes its new back back buffer.
     352             :    *
     353             :    * - a Layer wants to destroy its buffers.  Its ShadowableLayer
     354             :    *   calls Destroyed*Buffer(), which gives up control of the back
     355             :    *   buffer descriptor.  The actual back buffer surface is then
     356             :    *   destroyed using DestroySharedSurface() just before notifying
     357             :    *   the parent process.  When the parent process is notified, the
     358             :    *   LayerComposite also calls DestroySharedSurface() on its front
     359             :    *   buffer, and the double-buffer pair is gone.
     360             :    */
     361             : 
     362             :   virtual bool IPCOpen() const override;
     363             : 
     364             :   /**
     365             :    * Construct a shadow of |aLayer| on the "other side", at the
     366             :    * LayerManagerComposite.
     367             :    */
     368             :   LayerHandle ConstructShadowFor(ShadowableLayer* aLayer);
     369             : 
     370             :   /**
     371             :    * Flag the next paint as the first for a document.
     372             :    */
     373           3 :   void SetIsFirstPaint() { mIsFirstPaint = true; }
     374             : 
     375             :   /**
     376             :    * Set the current focus target to be sent with the next paint.
     377             :    */
     378          29 :   void SetFocusTarget(const FocusTarget& aFocusTarget) { mFocusTarget = aFocusTarget; }
     379             : 
     380             :   void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch);
     381             : 
     382             :   static void PlatformSyncBeforeUpdate();
     383             : 
     384             :   virtual bool AllocSurfaceDescriptor(const gfx::IntSize& aSize,
     385             :                                       gfxContentType aContent,
     386             :                                       SurfaceDescriptor* aBuffer) override;
     387             : 
     388             :   virtual bool AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
     389             :                                               gfxContentType aContent,
     390             :                                               uint32_t aCaps,
     391             :                                               SurfaceDescriptor* aBuffer) override;
     392             : 
     393             :   virtual void DestroySurfaceDescriptor(SurfaceDescriptor* aSurface) override;
     394             : 
     395             :   virtual void UpdateFwdTransactionId() override;
     396             :   virtual uint64_t GetFwdTransactionId() override;
     397             : 
     398             :   void ReleaseLayer(const LayerHandle& aHandle);
     399             : 
     400         129 :   bool InForwarderThread() override {
     401         129 :     return NS_IsMainThread();
     402             :   }
     403             : 
     404           0 :   PaintTiming& GetPaintTiming() {
     405           0 :     return mPaintTiming;
     406             :   }
     407             : 
     408           9 :   ShadowLayerForwarder* AsLayerForwarder() override { return this; }
     409             : 
     410             :   // Returns true if aSurface wraps a Shmem.
     411             :   static bool IsShmem(SurfaceDescriptor* aSurface);
     412             : 
     413             :   /**
     414             :    * Sends a synchronous ping to the compsoitor.
     415             :    *
     416             :    * This is bad for performance and should only be called as a last resort if the
     417             :    * compositor may be blocked for a long period of time, to avoid that the content
     418             :    * process accumulates resource allocations that the compositor is not consuming
     419             :    * and releasing.
     420             :    */
     421             :   void SyncWithCompositor();
     422             : 
     423         179 :   TextureForwarder* GetTextureForwarder() override { return GetCompositorBridgeChild(); }
     424           0 :   LayersIPCActor* GetLayersIPCActor() override { return this; }
     425             : 
     426           0 :   ActiveResourceTracker& GetActiveResourceTracker() { return *mActiveResourceTracker.get(); }
     427             : 
     428             :   CompositorBridgeChild* GetCompositorBridgeChild();
     429             : 
     430           9 :   nsIEventTarget* GetEventTarget() { return mEventTarget; };
     431             : 
     432             : protected:
     433             :   virtual ~ShadowLayerForwarder();
     434             : 
     435             :   explicit ShadowLayerForwarder(ClientLayerManager* aClientLayerManager);
     436             : 
     437             : #ifdef DEBUG
     438             :   void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const;
     439             : #else
     440             :   void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const {}
     441             : #endif
     442             : 
     443             :   RefPtr<CompositableClient> FindCompositable(const CompositableHandle& aHandle);
     444             : 
     445             :   bool InWorkerThread();
     446             : 
     447             :   RefPtr<LayerTransactionChild> mShadowManager;
     448             :   RefPtr<CompositorBridgeChild> mCompositorBridgeChild;
     449             : 
     450             : private:
     451             : 
     452             :   ClientLayerManager* mClientLayerManager;
     453             :   Transaction* mTxn;
     454             :   MessageLoop* mMessageLoop;
     455             :   DiagnosticTypes mDiagnosticTypes;
     456             :   bool mIsFirstPaint;
     457             :   FocusTarget mFocusTarget;
     458             :   bool mWindowOverlayChanged;
     459             :   InfallibleTArray<PluginWindowData> mPluginWindowData;
     460             :   UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
     461             :   uint64_t mNextLayerHandle;
     462             :   nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
     463             :   PaintTiming mPaintTiming;
     464             :   /**
     465             :    * ShadowLayerForwarder might dispatch tasks to main while puppet widget and
     466             :    * tabChild don't exist anymore; therefore we hold the event target since its
     467             :    *  lifecycle is independent of these objects.
     468             :    */
     469             :   nsCOMPtr<nsIEventTarget> mEventTarget;
     470             : };
     471             : 
     472             : class CompositableClient;
     473             : 
     474             : /**
     475             :  * A ShadowableLayer is a Layer can be shared with a parent context
     476             :  * through a ShadowLayerForwarder.  A ShadowableLayer maps to a
     477             :  * Shadow*Layer in a parent context.
     478             :  *
     479             :  * Note that ShadowLayers can themselves be ShadowableLayers.
     480             :  */
     481             : class ShadowableLayer
     482             : {
     483             : public:
     484             :   virtual ~ShadowableLayer();
     485             : 
     486             :   virtual Layer* AsLayer() = 0;
     487             : 
     488             :   /**
     489             :    * True if this layer has a shadow in a parent process.
     490             :    */
     491         218 :   bool HasShadow() { return mShadow.IsValid(); }
     492             : 
     493             :   /**
     494             :    * Return the IPC handle to a Shadow*Layer referring to this if one
     495             :    * exists, nullptr if not.
     496             :    */
     497         345 :   const LayerHandle& GetShadow() { return mShadow; }
     498             : 
     499          31 :   void SetShadow(ShadowLayerForwarder* aForwarder, const LayerHandle& aShadow) {
     500          31 :     MOZ_ASSERT(!mShadow, "can't have two shadows (yet)");
     501          31 :     mForwarder = aForwarder;
     502          31 :     mShadow = aShadow;
     503          31 :   }
     504             : 
     505           0 :   virtual CompositableClient* GetCompositableClient() { return nullptr; }
     506             : 
     507             : protected:
     508          31 :   ShadowableLayer() {}
     509             : 
     510             : private:
     511             :   RefPtr<ShadowLayerForwarder> mForwarder;
     512             :   LayerHandle mShadow;
     513             : };
     514             : 
     515             : } // namespace layers
     516             : } // namespace mozilla
     517             : 
     518             : #endif // ifndef mozilla_layers_ShadowLayers_h

Generated by: LCOV version 1.13