gfx/layers/ImageContainer.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 #ifndef GFX_IMAGECONTAINER_H
     7 #define GFX_IMAGECONTAINER_H
     9 #include <stdint.h>                     // for uint32_t, uint8_t, uint64_t
    10 #include <sys/types.h>                  // for int32_t
    11 #include "gfxTypes.h"
    12 #include "ImageTypes.h"                 // for ImageFormat, etc
    13 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
    14 #include "mozilla/Mutex.h"              // for Mutex
    15 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitorAutoEnter, etc
    16 #include "mozilla/TimeStamp.h"          // for TimeStamp
    17 #include "mozilla/gfx/Point.h"          // For IntSize
    18 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend, etc
    19 #include "mozilla/mozalloc.h"           // for operator delete, etc
    20 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoArrayPtr, etc
    21 #include "nsAutoRef.h"                  // for nsCountedRef
    22 #include "nsCOMPtr.h"                   // for already_AddRefed
    23 #include "nsDebug.h"                    // for NS_ASSERTION
    24 #include "nsISupportsImpl.h"            // for Image::Release, etc
    25 #include "nsRect.h"                     // for nsIntRect
    26 #include "nsSize.h"                     // for nsIntSize
    27 #include "nsTArray.h"                   // for nsTArray
    28 #include "mozilla/Atomics.h"
    29 #include "mozilla/WeakPtr.h"
    30 #include "nsThreadUtils.h"
    31 #include "mozilla/gfx/2D.h"
    32 #include "nsDataHashtable.h"
    33 #include "mozilla/EnumeratedArray.h"
    35 #ifndef XPCOM_GLUE_AVOID_NSPR
    36 /**
    37  * We need to be able to hold a reference to a Moz2D SourceSurface from Image
    38  * subclasses. This is potentially a problem since Images can be addrefed
    39  * or released off the main thread. We can ensure that we never AddRef
    40  * a SourceSurface off the main thread, but we might want to Release due
    41  * to an Image being destroyed off the main thread.
    42  *
    43  * We use nsCountedRef<nsMainThreadSourceSurfaceRef> to reference the
    44  * SourceSurface. When AddRefing, we assert that we're on the main thread.
    45  * When Releasing, if we're not on the main thread, we post an event to
    46  * the main thread to do the actual release.
    47  */
    48 class nsMainThreadSourceSurfaceRef;
    50 template <>
    51 class nsAutoRefTraits<nsMainThreadSourceSurfaceRef> {
    52 public:
    53   typedef mozilla::gfx::SourceSurface* RawRef;
    55   /**
    56    * The XPCOM event that will do the actual release on the main thread.
    57    */
    58   class SurfaceReleaser : public nsRunnable {
    59   public:
    60     SurfaceReleaser(RawRef aRef) : mRef(aRef) {}
    61     NS_IMETHOD Run() {
    62       mRef->Release();
    63       return NS_OK;
    64     }
    65     RawRef mRef;
    66   };
    68   static RawRef Void() { return nullptr; }
    69   static void Release(RawRef aRawRef)
    70   {
    71     if (NS_IsMainThread()) {
    72       aRawRef->Release();
    73       return;
    74     }
    75     nsCOMPtr<nsIRunnable> runnable = new SurfaceReleaser(aRawRef);
    76     NS_DispatchToMainThread(runnable);
    77   }
    78   static void AddRef(RawRef aRawRef)
    79   {
    80     NS_ASSERTION(NS_IsMainThread(),
    81                  "Can only add a reference on the main thread");
    82     aRawRef->AddRef();
    83   }
    84 };
    86 #endif
    88 #ifdef XP_WIN
    89 struct ID3D10Texture2D;
    90 struct ID3D10Device;
    91 struct ID3D10ShaderResourceView;
    92 #endif
    94 typedef void* HANDLE;
    96 namespace mozilla {
    98 class CrossProcessMutex;
   100 namespace layers {
   102 class ImageClient;
   103 class SharedPlanarYCbCrImage;
   104 class TextureClient;
   105 class CompositableClient;
   106 class CompositableForwarder;
   107 class SurfaceDescriptor;
   109 struct ImageBackendData
   110 {
   111   virtual ~ImageBackendData() {}
   113 protected:
   114   ImageBackendData() {}
   115 };
   117 // sadly we'll need this until we get rid of Deprected image classes
   118 class ISharedImage {
   119 public:
   120     virtual uint8_t* GetBuffer() = 0;
   122     /**
   123      * For use with the CompositableClient only (so that the later can
   124      * synchronize the TextureClient with the TextureHost).
   125      */
   126     virtual TextureClient* GetTextureClient(CompositableClient* aClient) = 0;
   127 };
   129 /**
   130  * A class representing a buffer of pixel data. The data can be in one
   131  * of various formats including YCbCr.
   132  * 
   133  * Create an image using an ImageContainer. Fill the image with data, and
   134  * then call ImageContainer::SetImage to display it. An image must not be
   135  * modified after calling SetImage. Image implementations do not need to
   136  * perform locking; when filling an Image, the Image client is responsible
   137  * for ensuring only one thread accesses the Image at a time, and after
   138  * SetImage the image is immutable.
   139  * 
   140  * When resampling an Image, only pixels within the buffer should be
   141  * sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
   142  */
   143 class Image {
   144   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image)
   146 public:
   147   virtual ISharedImage* AsSharedImage() { return nullptr; }
   149   ImageFormat GetFormat() { return mFormat; }
   150   void* GetImplData() { return mImplData; }
   152   virtual gfx::IntSize GetSize() = 0;
   153   virtual nsIntRect GetPictureRect()
   154   {
   155     return nsIntRect(0, 0, GetSize().width, GetSize().height);
   156   }
   158   ImageBackendData* GetBackendData(LayersBackend aBackend)
   159   { return mBackendData[aBackend]; }
   160   void SetBackendData(LayersBackend aBackend, ImageBackendData* aData)
   161   { mBackendData[aBackend] = aData; }
   163   int32_t GetSerial() { return mSerial; }
   165   void MarkSent() { mSent = true; }
   166   bool IsSentToCompositor() { return mSent; }
   168   virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
   170 protected:
   171   Image(void* aImplData, ImageFormat aFormat) :
   172     mImplData(aImplData),
   173     mSerial(++sSerialCounter),
   174     mFormat(aFormat),
   175     mSent(false)
   176   {}
   178   // Protected destructor, to discourage deletion outside of Release():
   179   virtual ~Image() {}
   181   mozilla::EnumeratedArray<mozilla::layers::LayersBackend,
   182                            mozilla::layers::LayersBackend::LAYERS_LAST,
   183                            nsAutoPtr<ImageBackendData>>
   184     mBackendData;
   186   void* mImplData;
   187   int32_t mSerial;
   188   ImageFormat mFormat;
   189   static mozilla::Atomic<int32_t> sSerialCounter;
   190   bool mSent;
   191 };
   193 /**
   194  * A RecycleBin is owned by an ImageContainer. We store buffers in it that we
   195  * want to recycle from one image to the next.It's a separate object from 
   196  * ImageContainer because images need to store a strong ref to their RecycleBin
   197  * and we must avoid creating a reference loop between an ImageContainer and
   198  * its active image.
   199  */
   200 class BufferRecycleBin MOZ_FINAL {
   201   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RecycleBin)
   203   //typedef mozilla::gl::GLContext GLContext;
   205 public:
   206   BufferRecycleBin();
   208   void RecycleBuffer(uint8_t* aBuffer, uint32_t aSize);
   209   // Returns a recycled buffer of the right size, or allocates a new buffer.
   210   uint8_t* GetBuffer(uint32_t aSize);
   212 private:
   213   typedef mozilla::Mutex Mutex;
   215   // Private destructor, to discourage deletion outside of Release():
   216   ~BufferRecycleBin()
   217   {
   218   }
   220   // This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures
   221   // and mRecycledTextureSizes
   222   Mutex mLock;
   224   // We should probably do something to prune this list on a timer so we don't
   225   // eat excess memory while video is paused...
   226   nsTArray<nsAutoArrayPtr<uint8_t> > mRecycledBuffers;
   227   // This is only valid if mRecycledBuffers is non-empty
   228   uint32_t mRecycledBufferSize;
   229 };
   231 class CompositionNotifySink
   232 {
   233 public:
   234   virtual void DidComposite() = 0;
   235   virtual ~CompositionNotifySink() {}
   236 };
   238 /**
   239  * A class that manages Image creation for a LayerManager. The only reason
   240  * we need a separate class here is that LayerManagers aren't threadsafe
   241  * (because layers can only be used on the main thread) and we want to
   242  * be able to create images from any thread, to facilitate video playback
   243  * without involving the main thread, for example.
   244  * Different layer managers can implement child classes of this making it
   245  * possible to create layer manager specific images.
   246  * This class is not meant to be used directly but rather can be set on an
   247  * image container. This is usually done by the layer system internally and
   248  * not explicitly by users. For PlanarYCbCr or Cairo images the default
   249  * implementation will creates images whose data lives in system memory, for
   250  * MacIOSurfaces the default implementation will be a simple MacIOSurface
   251  * wrapper.
   252  */
   254 class ImageFactory
   255 {
   256   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory)
   257 protected:
   258   friend class ImageContainer;
   260   ImageFactory() {}
   261   virtual ~ImageFactory() {}
   263   virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat,
   264                                               const gfx::IntSize &aScaleHint,
   265                                               BufferRecycleBin *aRecycleBin);
   267 };
   269 /**
   270  * This struct is used to store RemoteImages, it is meant to be able to live in
   271  * shared memory. Therefor it should not contain a vtable pointer. Remote
   272  * users can manipulate the data in this structure to specify what image is to
   273  * be drawn by the container. When accessing this data users should make sure
   274  * the mutex synchronizing access to the structure is held!
   275  */
   276 struct RemoteImageData {
   277   enum Type {
   278     /**
   279      * This is a format that uses raw bitmap data.
   280      */
   281     RAW_BITMAP,
   283     /**
   284      * This is a format that uses a pointer to a texture do draw directly
   285      * from a shared texture. Any process may have created this texture handle,
   286      * the process creating the texture handle is responsible for managing it's
   287      * lifetime by managing the lifetime of the first D3D texture object this
   288      * handle was created for. It must also ensure the handle is not set
   289      * current anywhere when the last reference to this object is released.
   290      */
   291     DXGI_TEXTURE_HANDLE
   292   };
   293   /* These formats describe the format in the memory byte-order */
   294   enum Format {
   295     /* 8 bits per channel */
   296     BGRA32,
   297     /* 8 bits per channel, alpha channel is ignored */
   298     BGRX32
   299   };
   301   // This should be set to true if a change was made so that the ImageContainer
   302   // knows to throw out any cached RemoteImage objects.
   303   bool mWasUpdated;
   304   Type mType;
   305   Format mFormat;
   306   gfx::IntSize mSize;
   307   union {
   308     struct {
   309       /* This pointer is set by a remote process, however it will be set to
   310        * the container process' address the memory of the raw bitmap resides
   311        * at.
   312        */
   313       unsigned char *mData;
   314       int mStride;
   315     } mBitmap;
   316 #ifdef XP_WIN
   317     HANDLE mTextureHandle;
   318 #endif
   319   };
   320 };
   322 /**
   323  * A class that manages Images for an ImageLayer. The only reason
   324  * we need a separate class here is that ImageLayers aren't threadsafe
   325  * (because layers can only be used on the main thread) and we want to
   326  * be able to set the current Image from any thread, to facilitate
   327  * video playback without involving the main thread, for example.
   328  *
   329  * An ImageContainer can operate in one of three modes:
   330  * 1) Normal. Triggered by constructing the ImageContainer with
   331  * DISABLE_ASYNC or when compositing is happening on the main thread.
   332  * SetCurrentImage changes ImageContainer state but nothing is sent to the
   333  * compositor until the next layer transaction.
   334  * 2) Asynchronous. Initiated by constructing the ImageContainer with
   335  * ENABLE_ASYNC when compositing is happening on the main thread.
   336  * SetCurrentImage sends a message through the ImageBridge to the compositor
   337  * thread to update the image, without going through the main thread or
   338  * a layer transaction.
   339  * 3) Remote. Initiated by calling SetRemoteImageData on the ImageContainer
   340  * before any other activity.
   341  * The ImageContainer uses a shared memory block containing a cross-process mutex
   342  * to communicate with the compositor thread. SetCurrentImage synchronously
   343  * updates the shared state to point to the new image and the old image
   344  * is immediately released (not true in Normal or Asynchronous modes).
   345  */
   346 class ImageContainer MOZ_FINAL : public SupportsWeakPtr<ImageContainer> {
   347   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
   348 public:
   349   MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageContainer)
   351   enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
   353   ImageContainer(int flag = 0);
   355   /**
   356    * Create an Image in one of the given formats.
   357    * Picks the "best" format from the list and creates an Image of that
   358    * format.
   359    * Returns null if this backend does not support any of the formats.
   360    * Can be called on any thread. This method takes mReentrantMonitor
   361    * when accessing thread-shared state.
   362    */
   363   already_AddRefed<Image> CreateImage(ImageFormat aFormat);
   365   /**
   366    * Set an Image as the current image to display. The Image must have
   367    * been created by this ImageContainer.
   368    * Can be called on any thread. This method takes mReentrantMonitor
   369    * when accessing thread-shared state.
   370    * aImage can be null. While it's null, nothing will be painted.
   371    * 
   372    * The Image data must not be modified after this method is called!
   373    * Note that this must not be called if ENABLE_ASYNC has not been set.
   374    *
   375    * Implementations must call CurrentImageChanged() while holding
   376    * mReentrantMonitor.
   377    *
   378    * If this ImageContainer has an ImageClient for async video:
   379    * Schelude a task to send the image to the compositor using the 
   380    * PImageBridge protcol without using the main thread.
   381    */
   382   void SetCurrentImage(Image* aImage);
   384   /**
   385    * Clear all images. Let ImageClient release all TextureClients.
   386    */
   387   void ClearAllImages();
   389   /**
   390    * Clear all images except current one.
   391    * Let ImageClient release all TextureClients except front one.
   392    */
   393   void ClearAllImagesExceptFront();
   395   /**
   396    * Clear the current image.
   397    * This function is expect to be called only from a CompositableClient
   398    * that belongs to ImageBridgeChild. Created to prevent dead lock.
   399    * See Bug 901224.
   400    */
   401   void ClearCurrentImage();
   403   /**
   404    * Set an Image as the current image to display. The Image must have
   405    * been created by this ImageContainer.
   406    * Must be called on the main thread, within a layers transaction.
   407    * 
   408    * This method takes mReentrantMonitor
   409    * when accessing thread-shared state.
   410    * aImage can be null. While it's null, nothing will be painted.
   411    * 
   412    * The Image data must not be modified after this method is called!
   413    * Note that this must not be called if ENABLE_ASYNC been set.
   414    *
   415    * Implementations must call CurrentImageChanged() while holding
   416    * mReentrantMonitor.
   417    */
   418   void SetCurrentImageInTransaction(Image* aImage);
   420   /**
   421    * Returns true if this ImageContainer uses the ImageBridge IPDL protocol.
   422    *
   423    * Can be called from any thread.
   424    */
   425   bool IsAsync() const;
   427   /**
   428    * If this ImageContainer uses ImageBridge, returns the ID associated to
   429    * this container, for use in the ImageBridge protocol.
   430    * Returns 0 if this ImageContainer does not use ImageBridge. Note that
   431    * 0 is always an invalid ID for asynchronous image containers.
   432    *
   433    * Can be called from any thread.
   434    */
   435   uint64_t GetAsyncContainerID() const;
   437   /**
   438    * Returns if the container currently has an image.
   439    * Can be called on any thread. This method takes mReentrantMonitor
   440    * when accessing thread-shared state.
   441    */
   442   bool HasCurrentImage();
   444   /**
   445    * Lock the current Image.
   446    * This has to add a reference since otherwise there are race conditions
   447    * where the current image is destroyed before the caller can add
   448    * a reference. This lock strictly guarantees the underlying image remains
   449    * valid, it does not mean the current image cannot change.
   450    * Can be called on any thread. This method will lock the cross-process
   451    * mutex to ensure remote processes cannot alter underlying data. This call
   452    * -must- be balanced by a call to UnlockCurrentImage and users should avoid
   453    * holding the image locked for a long time.
   454    */
   455   already_AddRefed<Image> LockCurrentImage();
   457   /**
   458    * This call unlocks the image. For remote images releasing the cross-process
   459    * mutex.
   460    */
   461   void UnlockCurrentImage();
   463   /**
   464    * Get the current image as a SourceSurface. This is useful for fallback
   465    * rendering.
   466    * This can only be called from the main thread, since cairo objects
   467    * can only be used from the main thread.
   468    * This is defined here and not on Image because it's possible (likely)
   469    * that some backends will make an Image "ready to draw" only when it
   470    * becomes the current image for an image container.
   471    * Returns null if there is no current image.
   472    * Returns the size in aSize.
   473    * The returned surface will never be modified. The caller must not
   474    * modify it.
   475    * Can be called on any thread. This method takes mReentrantMonitor
   476    * when accessing thread-shared state.
   477    * If the current image is a remote image, that is, if it is an image that
   478    * may be shared accross processes, calling this function will make
   479    * a copy of the image data while holding the mRemoteDataMutex. If possible,
   480    * the lock methods should be used to avoid the copy, however this should be
   481    * avoided if the surface is required for a long period of time.
   482    */
   483   TemporaryRef<gfx::SourceSurface> GetCurrentAsSourceSurface(gfx::IntSize* aSizeResult);
   485   /**
   486    * Same as LockCurrentAsSurface but for Moz2D
   487    */
   488   TemporaryRef<gfx::SourceSurface> LockCurrentAsSourceSurface(gfx::IntSize* aSizeResult,
   489                                                               Image** aCurrentImage = nullptr);
   491   /**
   492    * Returns the size of the image in pixels.
   493    * Can be called on any thread. This method takes mReentrantMonitor when accessing
   494    * thread-shared state.
   495    */
   496   gfx::IntSize GetCurrentSize();
   498   /**
   499    * Sets a size that the image is expected to be rendered at.
   500    * This is a hint for image backends to optimize scaling.
   501    * Default implementation in this class is to ignore the hint.
   502    * Can be called on any thread. This method takes mReentrantMonitor
   503    * when accessing thread-shared state.
   504    */
   505   void SetScaleHint(const gfx::IntSize& aScaleHint)
   506   { mScaleHint = aScaleHint; }
   508   void SetImageFactory(ImageFactory *aFactory)
   509   {
   510     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   511     mImageFactory = aFactory ? aFactory : new ImageFactory();
   512   }
   514   /**
   515    * Returns the time at which the currently contained image was first
   516    * painted.  This is reset every time a new image is set as the current
   517    * image.  Note this may return a null timestamp if the current image
   518    * has not yet been painted.  Can be called from any thread.
   519    */
   520   TimeStamp GetPaintTime() {
   521     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   522     return mPaintTime;
   523   }
   525   /**
   526    * Returns the number of images which have been contained in this container
   527    * and painted at least once.  Can be called from any thread.
   528    */
   529   uint32_t GetPaintCount() {
   530     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   531     return mPaintCount;
   532   }
   534   /**
   535    * Resets the paint count to zero.
   536    * Can be called from any thread.
   537    */
   538   void ResetPaintCount() {
   539     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   540     mPaintCount = 0;
   541   }
   543   /**
   544    * Increments mPaintCount if this is the first time aPainted has been
   545    * painted, and sets mPaintTime if the painted image is the current image.
   546    * current image.  Can be called from any thread.
   547    */
   548   void NotifyPaintedImage(Image* aPainted) {
   549     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   551     nsRefPtr<Image> current = mActiveImage;
   552     if (aPainted == current) {
   553       if (mPaintTime.IsNull()) {
   554         mPaintTime = TimeStamp::Now();
   555         mPaintCount++;
   556       }
   557     } else if (!mPreviousImagePainted) {
   558       // While we were painting this image, the current image changed. We
   559       // still must count it as painted, but can't set mPaintTime, since we're
   560       // no longer the current image.
   561       mPaintCount++;
   562       mPreviousImagePainted = true;
   563     }
   565     if (mCompositionNotifySink) {
   566       mCompositionNotifySink->DidComposite();
   567     }
   568   }
   570   void SetCompositionNotifySink(CompositionNotifySink *aSink) {
   571     mCompositionNotifySink = aSink;
   572   }
   574   /**
   575    * This function is called to tell the ImageContainer where the
   576    * (cross-process) segment lives where the shared data about possible
   577    * remote images are stored. In addition to this a CrossProcessMutex object
   578    * is passed telling the container how to synchronize access to this data.
   579    * NOTE: This should be called during setup of the container and not after
   580    * usage has started.
   581    */
   582   void SetRemoteImageData(RemoteImageData *aRemoteData,
   583                           CrossProcessMutex *aRemoteDataMutex);
   584   /**
   585    * This can be used to check if the container has RemoteData set.
   586    */
   587   RemoteImageData *GetRemoteImageData() { return mRemoteData; }
   589 private:
   590   typedef mozilla::ReentrantMonitor ReentrantMonitor;
   592   // Private destructor, to discourage deletion outside of Release():
   593   ~ImageContainer();
   595   void SetCurrentImageInternal(Image* aImage);
   597   // This is called to ensure we have an active image, this may not be true
   598   // when we're storing image information in a RemoteImageData structure.
   599   // NOTE: If we have remote data mRemoteDataMutex should be locked when
   600   // calling this function!
   601   void EnsureActiveImage();
   603   // ReentrantMonitor to protect thread safe access to the "current
   604   // image", and any other state which is shared between threads.
   605   ReentrantMonitor mReentrantMonitor;
   607   // Performs necessary housekeeping to ensure the painted frame statistics
   608   // are accurate. Must be called by SetCurrentImage() implementations with
   609   // mReentrantMonitor held.
   610   void CurrentImageChanged() {
   611     mReentrantMonitor.AssertCurrentThreadIn();
   612     mPreviousImagePainted = !mPaintTime.IsNull();
   613     mPaintTime = TimeStamp();
   614   }
   616   nsRefPtr<Image> mActiveImage;
   618   // Number of contained images that have been painted at least once.  It's up
   619   // to the ImageContainer implementation to ensure accesses to this are
   620   // threadsafe.
   621   uint32_t mPaintCount;
   623   // Time stamp at which the current image was first painted.  It's up to the
   624   // ImageContainer implementation to ensure accesses to this are threadsafe.
   625   TimeStamp mPaintTime;
   627   // Denotes whether the previous image was painted.
   628   bool mPreviousImagePainted;
   630   // This is the image factory used by this container, layer managers using
   631   // this container can set an alternative image factory that will be used to
   632   // create images for this container.
   633   nsRefPtr<ImageFactory> mImageFactory;
   635   gfx::IntSize mScaleHint;
   637   nsRefPtr<BufferRecycleBin> mRecycleBin;
   639   // This contains the remote image data for this container, if this is nullptr
   640   // that means the container has no other process that may control its active
   641   // image.
   642   RemoteImageData *mRemoteData;
   644   // This cross-process mutex is used to synchronise access to mRemoteData.
   645   // When this mutex is held, we will always be inside the mReentrantMonitor
   646   // however the same is not true vice versa.
   647   CrossProcessMutex *mRemoteDataMutex;
   649   CompositionNotifySink *mCompositionNotifySink;
   651   // This member points to an ImageClient if this ImageContainer was
   652   // sucessfully created with ENABLE_ASYNC, or points to null otherwise.
   653   // 'unsuccessful' in this case only means that the ImageClient could not
   654   // be created, most likely because off-main-thread compositing is not enabled.
   655   // In this case the ImageContainer is perfectly usable, but it will forward
   656   // frames to the compositor through transactions in the main thread rather than
   657   // asynchronusly using the ImageBridge IPDL protocol.
   658   ImageClient* mImageClient;
   659 };
   661 class AutoLockImage
   662 {
   663 public:
   664   AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
   665   AutoLockImage(ImageContainer *aContainer, RefPtr<gfx::SourceSurface> *aSurface) : mContainer(aContainer) {
   666     *aSurface = mContainer->LockCurrentAsSourceSurface(&mSize, getter_AddRefs(mImage));
   667   }
   668   ~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } }
   670   Image* GetImage() { return mImage; }
   671   const gfx::IntSize &GetSize() { return mSize; }
   673   void Unlock() { 
   674     if (mContainer) {
   675       mImage = nullptr;
   676       mContainer->UnlockCurrentImage();
   677       mContainer = nullptr;
   678     }
   679   }
   681   /** Things get a little tricky here, because our underlying image can -still-
   682    * change, and OS X requires a complicated callback mechanism to update this
   683    * we need to support staying the lock and getting the new image in a proper
   684    * way. This method makes any images retrieved with GetImage invalid!
   685    */
   686   void Refresh() {
   687     if (mContainer) {
   688       mContainer->UnlockCurrentImage();
   689       mImage = mContainer->LockCurrentImage();
   690     }
   691   }
   693 private:
   694   ImageContainer *mContainer;
   695   nsRefPtr<Image> mImage;
   696   gfx::IntSize mSize;
   697 };
   699 struct PlanarYCbCrData {
   700   // Luminance buffer
   701   uint8_t* mYChannel;
   702   int32_t mYStride;
   703   gfx::IntSize mYSize;
   704   int32_t mYSkip;
   705   // Chroma buffers
   706   uint8_t* mCbChannel;
   707   uint8_t* mCrChannel;
   708   int32_t mCbCrStride;
   709   gfx::IntSize mCbCrSize;
   710   int32_t mCbSkip;
   711   int32_t mCrSkip;
   712   // Picture region
   713   uint32_t mPicX;
   714   uint32_t mPicY;
   715   gfx::IntSize mPicSize;
   716   StereoMode mStereoMode;
   718   nsIntRect GetPictureRect() const {
   719     return nsIntRect(mPicX, mPicY,
   720                      mPicSize.width,
   721                      mPicSize.height);
   722   }
   724   PlanarYCbCrData()
   725     : mYChannel(nullptr), mYStride(0), mYSize(0, 0), mYSkip(0)
   726     , mCbChannel(nullptr), mCrChannel(nullptr)
   727     , mCbCrStride(0), mCbCrSize(0, 0) , mCbSkip(0), mCrSkip(0)
   728     , mPicX(0), mPicY(0), mPicSize(0, 0), mStereoMode(StereoMode::MONO)
   729   {}
   730 };
   732 /****** Image subtypes for the different formats ******/
   734 /**
   735  * We assume that the image data is in the REC 470M color space (see
   736  * Theora specification, section 4.3.1).
   737  *
   738  * The YCbCr format can be:
   739  *
   740  * 4:4:4 - CbCr width/height are the same as Y.
   741  * 4:2:2 - CbCr width is half that of Y. Height is the same.
   742  * 4:2:0 - CbCr width and height is half that of Y.
   743  *
   744  * The color format is detected based on the height/width ratios
   745  * defined above.
   746  * 
   747  * The Image that is rendered is the picture region defined by
   748  * mPicX, mPicY and mPicSize. The size of the rendered image is
   749  * mPicSize, not mYSize or mCbCrSize.
   750  *
   751  * mYSkip, mCbSkip, mCrSkip are added to support various output
   752  * formats from hardware decoder. They are per-pixel skips in the
   753  * source image.
   754  *
   755  * For example when image width is 640, mYStride is 670, mYSkip is 3,
   756  * the mYChannel buffer looks like:
   757  *
   758  * |<----------------------- mYStride ----------------------------->|
   759  * |<----------------- mYSize.width --------------->|
   760  *  0   3   6   9   12  15  18  21                659             669
   761  * |----------------------------------------------------------------|
   762  * |Y___Y___Y___Y___Y___Y___Y___Y...                      |%%%%%%%%%|
   763  * |Y___Y___Y___Y___Y___Y___Y___Y...                      |%%%%%%%%%|
   764  * |Y___Y___Y___Y___Y___Y___Y___Y...                      |%%%%%%%%%|
   765  * |            |<->|
   766  *                mYSkip
   767  */
   768 class PlanarYCbCrImage : public Image {
   769 public:
   770   typedef PlanarYCbCrData Data;
   772   enum {
   773     MAX_DIMENSION = 16384
   774   };
   776   virtual ~PlanarYCbCrImage();
   778   /**
   779    * This makes a copy of the data buffers, in order to support functioning
   780    * in all different layer managers.
   781    */
   782   virtual void SetData(const Data& aData);
   784   /**
   785    * This doesn't make a copy of the data buffers. Can be used when mBuffer is
   786    * pre allocated with AllocateAndGetNewBuffer(size) and then SetDataNoCopy is
   787    * called to only update the picture size, planes etc. fields in mData.
   788    * The GStreamer media backend uses this to decode into PlanarYCbCrImage(s)
   789    * directly.
   790    */
   791   virtual void SetDataNoCopy(const Data &aData);
   793   /**
   794    * This allocates and returns a new buffer
   795    */
   796   virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize);
   798   /**
   799    * Ask this Image to not convert YUV to RGB during SetData, and make
   800    * the original data available through GetData. This is optional,
   801    * and not all PlanarYCbCrImages will support it.
   802    */
   803   virtual void SetDelayedConversion(bool aDelayed) { }
   805   /**
   806    * Grab the original YUV data. This is optional.
   807    */
   808   virtual const Data* GetData() { return &mData; }
   810   /**
   811    * Return the number of bytes of heap memory used to store this image.
   812    */
   813   virtual uint32_t GetDataSize() { return mBufferSize; }
   815   virtual bool IsValid() { return !!mBufferSize; }
   817   virtual gfx::IntSize GetSize() { return mSize; }
   819   PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
   821   virtual SharedPlanarYCbCrImage *AsSharedPlanarYCbCrImage() { return nullptr; }
   823   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
   824     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   825   }
   827   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
   829 protected:
   830   /**
   831    * Make a copy of the YCbCr data into local storage.
   832    *
   833    * @param aData           Input image data.
   834    */
   835   void CopyData(const Data& aData);
   837   /**
   838    * Return a buffer to store image data in.
   839    * The default implementation returns memory that can
   840    * be freed wit delete[]
   841    */
   842   virtual uint8_t* AllocateBuffer(uint32_t aSize);
   844   TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
   846   void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
   847   gfxImageFormat GetOffscreenFormat();
   849   nsAutoArrayPtr<uint8_t> mBuffer;
   850   uint32_t mBufferSize;
   851   Data mData;
   852   gfx::IntSize mSize;
   853   gfxImageFormat mOffscreenFormat;
   854   nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
   855   nsRefPtr<BufferRecycleBin> mRecycleBin;
   856 };
   858 /**
   859  * Currently, the data in a CairoImage surface is treated as being in the
   860  * device output color space. This class is very simple as all backends
   861  * have to know about how to deal with drawing a cairo image.
   862  */
   863 class CairoImage : public Image,
   864                    public ISharedImage {
   865 public:
   866   struct Data {
   867     gfx::IntSize mSize;
   868     RefPtr<gfx::SourceSurface> mSourceSurface;
   869   };
   871   /**
   872    * This can only be called on the main thread. It may add a reference
   873    * to the surface (which will eventually be released on the main thread).
   874    * The surface must not be modified after this call!!!
   875    */
   876   void SetData(const Data& aData)
   877   {
   878     mSize = aData.mSize;
   879     mSourceSurface = aData.mSourceSurface;
   880   }
   882   virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface()
   883   {
   884     return mSourceSurface.get();
   885   }
   887   virtual ISharedImage* AsSharedImage() { return this; }
   888   virtual uint8_t* GetBuffer() { return nullptr; }
   889   virtual TextureClient* GetTextureClient(CompositableClient* aClient);
   891   gfx::IntSize GetSize() { return mSize; }
   893   CairoImage();
   894   ~CairoImage();
   896   gfx::IntSize mSize;
   898   nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
   899   nsDataHashtable<nsUint32HashKey, RefPtr<TextureClient> >  mTextureClients;
   900 };
   902 class RemoteBitmapImage : public Image {
   903 public:
   904   RemoteBitmapImage() : Image(nullptr, ImageFormat::REMOTE_IMAGE_BITMAP) {}
   906   TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
   908   gfx::IntSize GetSize() { return mSize; }
   910   unsigned char *mData;
   911   int mStride;
   912   gfx::IntSize mSize;
   913   RemoteImageData::Format mFormat;
   914 };
   916 } //namespace
   917 } //namespace
   919 #endif

mercurial