LCOV - code coverage report
Current view: top level - gfx/layers/basic - BasicCompositor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 173 485 35.7 %
Date: 2017-07-14 16:53:18 Functions: 26 65 40.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             : * This Source Code Form is subject to the terms of the Mozilla Public
       3             : * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "BasicCompositor.h"
       7             : #include "BasicLayersImpl.h"            // for FillRectWithMask
       8             : #include "TextureHostBasic.h"
       9             : #include "mozilla/layers/Effects.h"
      10             : #include "nsIWidget.h"
      11             : #include "gfx2DGlue.h"
      12             : #include "mozilla/gfx/2D.h"
      13             : #include "mozilla/gfx/gfxVars.h"
      14             : #include "mozilla/gfx/Helpers.h"
      15             : #include "mozilla/gfx/Tools.h"
      16             : #include "mozilla/gfx/ssse3-scaler.h"
      17             : #include "mozilla/layers/ImageDataSerializer.h"
      18             : #include "mozilla/SSE.h"
      19             : #include "gfxUtils.h"
      20             : #include "YCbCrUtils.h"
      21             : #include <algorithm>
      22             : #include "ImageContainer.h"
      23             : #include "gfxPrefs.h"
      24             : 
      25             : namespace mozilla {
      26             : using namespace mozilla::gfx;
      27             : 
      28             : namespace layers {
      29             : 
      30          18 : class DataTextureSourceBasic : public DataTextureSource
      31             :                              , public TextureSourceBasic
      32             : {
      33             : public:
      34           0 :   virtual const char* Name() const override { return "DataTextureSourceBasic"; }
      35             : 
      36           9 :   explicit DataTextureSourceBasic(DataSourceSurface* aSurface)
      37           9 :   : mSurface(aSurface)
      38           9 :   , mWrappingExistingData(!!aSurface)
      39           9 :   {}
      40             : 
      41           0 :   virtual DataTextureSource* AsDataTextureSource() override
      42             :   {
      43             :     // If the texture wraps someone else's memory we'd rather not use it as
      44             :     // a DataTextureSource per say (that is call Update on it).
      45           0 :     return mWrappingExistingData ? nullptr : this;
      46             :   }
      47             : 
      48          56 :   virtual TextureSourceBasic* AsSourceBasic() override { return this; }
      49             : 
      50          56 :   virtual gfx::SourceSurface* GetSurface(DrawTarget* aTarget) override { return mSurface; }
      51             : 
      52          56 :   SurfaceFormat GetFormat() const override
      53             :   {
      54          56 :     return mSurface ? mSurface->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
      55             :   }
      56             : 
      57          56 :   virtual IntSize GetSize() const override
      58             :   {
      59          56 :     return mSurface ? mSurface->GetSize() : gfx::IntSize(0, 0);
      60             :   }
      61             : 
      62           0 :   virtual bool Update(gfx::DataSourceSurface* aSurface,
      63             :                       nsIntRegion* aDestRegion = nullptr,
      64             :                       gfx::IntPoint* aSrcOffset = nullptr) override
      65             :   {
      66           0 :     MOZ_ASSERT(!mWrappingExistingData);
      67           0 :     if (mWrappingExistingData) {
      68           0 :       return false;
      69             :     }
      70           0 :     mSurface = aSurface;
      71           0 :     return true;
      72             :   }
      73             : 
      74           6 :   virtual void DeallocateDeviceData() override
      75             :   {
      76           6 :     mSurface = nullptr;
      77           6 :     SetUpdateSerial(0);
      78           6 :   }
      79             : 
      80             : public:
      81             :   RefPtr<gfx::DataSourceSurface> mSurface;
      82             :   bool mWrappingExistingData;
      83             : };
      84             : 
      85             : /**
      86             :  * WrappingTextureSourceYCbCrBasic wraps YUV format BufferTextureHost to defer
      87             :  * yuv->rgb conversion. The conversion happens when GetSurface is called.
      88             :  */
      89           0 : class WrappingTextureSourceYCbCrBasic : public DataTextureSource
      90             :                                       , public TextureSourceBasic
      91             : {
      92             : public:
      93           0 :   virtual const char* Name() const override { return "WrappingTextureSourceYCbCrBasic"; }
      94             : 
      95           0 :   explicit WrappingTextureSourceYCbCrBasic(BufferTextureHost* aTexture)
      96           0 :   : mTexture(aTexture)
      97           0 :   , mSize(aTexture->GetSize())
      98           0 :   , mNeedsUpdate(true)
      99             :   {
     100           0 :     mFromYCBCR = true;
     101           0 :   }
     102             : 
     103           0 :   virtual DataTextureSource* AsDataTextureSource() override
     104             :   {
     105           0 :     return this;
     106             :   }
     107             : 
     108           0 :   virtual TextureSourceBasic* AsSourceBasic() override { return this; }
     109             : 
     110           0 :   virtual WrappingTextureSourceYCbCrBasic* AsWrappingTextureSourceYCbCrBasic() override { return this; }
     111             : 
     112           0 :   virtual gfx::SourceSurface* GetSurface(DrawTarget* aTarget) override
     113             :   {
     114           0 :     if (mSurface && !mNeedsUpdate) {
     115           0 :       return mSurface;
     116             :     }
     117           0 :     MOZ_ASSERT(mTexture);
     118           0 :     if (!mTexture) {
     119           0 :       return nullptr;
     120             :     }
     121             : 
     122           0 :     if (!mSurface) {
     123           0 :       mSurface = Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8);
     124             :     }
     125           0 :     if (!mSurface) {
     126           0 :       return nullptr;
     127             :     }
     128           0 :     MOZ_ASSERT(mTexture->GetBufferDescriptor().type() == BufferDescriptor::TYCbCrDescriptor);
     129           0 :     MOZ_ASSERT(mTexture->GetSize() == mSize);
     130             : 
     131             :     mSurface =
     132           0 :       ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
     133           0 :         mTexture->GetBuffer(),
     134           0 :         mTexture->GetBufferDescriptor().get_YCbCrDescriptor(),
     135           0 :         mSurface);
     136           0 :     mNeedsUpdate = false;
     137           0 :     return mSurface;
     138             :   }
     139             : 
     140           0 :   SurfaceFormat GetFormat() const override
     141             :   {
     142           0 :     return gfx::SurfaceFormat::B8G8R8X8;
     143             :   }
     144             : 
     145           0 :   virtual IntSize GetSize() const override
     146             :   {
     147           0 :     return mSize;
     148             :   }
     149             : 
     150           0 :   virtual bool Update(gfx::DataSourceSurface* aSurface,
     151             :                       nsIntRegion* aDestRegion = nullptr,
     152             :                       gfx::IntPoint* aSrcOffset = nullptr) override
     153             :   {
     154           0 :     return false;
     155             :   }
     156             : 
     157           0 :   virtual void DeallocateDeviceData() override
     158             :   {
     159           0 :     mTexture = nullptr;
     160           0 :     mSurface = nullptr;
     161           0 :     SetUpdateSerial(0);
     162           0 :   }
     163             : 
     164           0 :   virtual void Unbind() override
     165             :   {
     166           0 :     mNeedsUpdate = true;
     167           0 :   }
     168             : 
     169           0 :   void SetBufferTextureHost(BufferTextureHost* aTexture) override
     170             :   {
     171           0 :     mTexture = aTexture;
     172           0 :     mNeedsUpdate = true;
     173           0 :   }
     174             : 
     175           0 :   void ConvertAndScale(const SurfaceFormat& aDestFormat,
     176             :                        const IntSize& aDestSize,
     177             :                        unsigned char* aDestBuffer,
     178             :                        int32_t aStride)
     179             :   {
     180           0 :     MOZ_ASSERT(mTexture);
     181           0 :     if (!mTexture) {
     182           0 :       return;
     183             :     }
     184           0 :     MOZ_ASSERT(mTexture->GetBufferDescriptor().type() == BufferDescriptor::TYCbCrDescriptor);
     185           0 :     MOZ_ASSERT(mTexture->GetSize() == mSize);
     186           0 :     ImageDataSerializer::ConvertAndScaleFromYCbCrDescriptor(
     187           0 :       mTexture->GetBuffer(),
     188           0 :       mTexture->GetBufferDescriptor().get_YCbCrDescriptor(),
     189             :       aDestFormat,
     190             :       aDestSize,
     191             :       aDestBuffer,
     192           0 :       aStride);
     193             :   }
     194             : public:
     195             :   BufferTextureHost* mTexture;
     196             :   const gfx::IntSize mSize;
     197             :   RefPtr<gfx::DataSourceSurface> mSurface;
     198             :   bool mNeedsUpdate;
     199             : };
     200             : 
     201           1 : BasicCompositor::BasicCompositor(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget)
     202             :   : Compositor(aWidget, aParent)
     203           1 :   , mIsPendingEndRemoteDrawing(false)
     204             : {
     205           1 :   MOZ_COUNT_CTOR(BasicCompositor);
     206             : 
     207           1 :   mMaxTextureSize = Factory::GetMaxSurfaceSize(gfxVars::ContentBackend());
     208           1 : }
     209             : 
     210           0 : BasicCompositor::~BasicCompositor()
     211             : {
     212           0 :   MOZ_COUNT_DTOR(BasicCompositor);
     213           0 : }
     214             : 
     215             : bool
     216           1 : BasicCompositor::Initialize(nsCString* const out_failureReason)
     217             : {
     218           1 :   return mWidget ? mWidget->InitCompositor(this) : false;
     219             : };
     220             : 
     221             : int32_t
     222           1 : BasicCompositor::GetMaxTextureSize() const
     223             : {
     224           1 :   return mMaxTextureSize;
     225             : }
     226             : 
     227             : void
     228          27 : BasicCompositingRenderTarget::BindRenderTarget()
     229             : {
     230          27 :   if (mClearOnBind) {
     231           0 :     mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height));
     232           0 :     mClearOnBind = false;
     233             :   }
     234          27 : }
     235             : 
     236           0 : void BasicCompositor::DetachWidget()
     237             : {
     238           0 :   if (mWidget) {
     239           0 :     if (mIsPendingEndRemoteDrawing) {
     240             :       // Force to end previous remote drawing.
     241           0 :       TryToEndRemoteDrawing(/* aForceToEnd */ true);
     242           0 :       MOZ_ASSERT(!mIsPendingEndRemoteDrawing);
     243             :     }
     244           0 :     mWidget->CleanupRemoteDrawing();
     245             :   }
     246           0 :   Compositor::DetachWidget();
     247           0 : }
     248             : 
     249             : TextureFactoryIdentifier
     250           1 : BasicCompositor::GetTextureFactoryIdentifier()
     251             : {
     252             :   TextureFactoryIdentifier ident(LayersBackend::LAYERS_BASIC,
     253             :                                  XRE_GetProcessType(),
     254           1 :                                  GetMaxTextureSize());
     255           1 :   return ident;
     256             : }
     257             : 
     258             : already_AddRefed<CompositingRenderTarget>
     259           0 : BasicCompositor::CreateRenderTarget(const IntRect& aRect, SurfaceInitMode aInit)
     260             : {
     261           0 :   MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
     262             : 
     263           0 :   if (aRect.width * aRect.height == 0) {
     264           0 :     return nullptr;
     265             :   }
     266             : 
     267           0 :   RefPtr<DrawTarget> target = mDrawTarget->CreateSimilarDrawTarget(aRect.Size(), SurfaceFormat::B8G8R8A8);
     268             : 
     269           0 :   if (!target) {
     270           0 :     return nullptr;
     271             :   }
     272             : 
     273           0 :   RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(target, aRect);
     274             : 
     275           0 :   return rt.forget();
     276             : }
     277             : 
     278             : already_AddRefed<CompositingRenderTarget>
     279           0 : BasicCompositor::CreateRenderTargetFromSource(const IntRect &aRect,
     280             :                                               const CompositingRenderTarget *aSource,
     281             :                                               const IntPoint &aSourcePoint)
     282             : {
     283           0 :   MOZ_CRASH("GFX: Shouldn't be called!");
     284             :   return nullptr;
     285             : }
     286             : 
     287             : already_AddRefed<CompositingRenderTarget>
     288          27 : BasicCompositor::CreateRenderTargetForWindow(const LayoutDeviceIntRect& aRect, const LayoutDeviceIntRect& aClearRect, BufferMode aBufferMode)
     289             : {
     290          27 :   MOZ_ASSERT(mDrawTarget);
     291          27 :   MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
     292             : 
     293          27 :   if (aRect.width * aRect.height == 0) {
     294           0 :     return nullptr;
     295             :   }
     296             : 
     297          54 :   RefPtr<BasicCompositingRenderTarget> rt;
     298          27 :   IntRect rect = aRect.ToUnknownRect();
     299             : 
     300          27 :   if (aBufferMode != BufferMode::BUFFER_NONE) {
     301           0 :     RefPtr<DrawTarget> target = mWidget->GetBackBufferDrawTarget(mDrawTarget, aRect, aClearRect);
     302           0 :     if (!target) {
     303           0 :       return nullptr;
     304             :     }
     305           0 :     MOZ_ASSERT(target != mDrawTarget);
     306           0 :     rt = new BasicCompositingRenderTarget(target, rect);
     307             :   } else {
     308          27 :     IntRect windowRect = rect;
     309             :     // Adjust bounds rect to account for new origin at (0, 0).
     310          27 :     if (windowRect.Size() != mDrawTarget->GetSize()) {
     311           0 :       windowRect.ExpandToEnclose(IntPoint(0, 0));
     312             :     }
     313          54 :     rt = new BasicCompositingRenderTarget(mDrawTarget, windowRect);
     314          27 :     if (!aClearRect.IsEmpty()) {
     315           1 :       IntRect clearRect = aRect.ToUnknownRect();
     316           1 :       mDrawTarget->ClearRect(Rect(clearRect - rt->GetOrigin()));
     317             :     }
     318             :   }
     319             : 
     320          27 :   return rt.forget();
     321             : }
     322             : 
     323             : already_AddRefed<DataTextureSource>
     324           0 : BasicCompositor::CreateDataTextureSource(TextureFlags aFlags)
     325             : {
     326           0 :   RefPtr<DataTextureSourceBasic> result = new DataTextureSourceBasic(nullptr);
     327           0 :   if (aFlags & TextureFlags::RGB_FROM_YCBCR) {
     328           0 :       result->mFromYCBCR = true;
     329             :   }
     330           0 :   return result.forget();
     331             : }
     332             : 
     333             : already_AddRefed<DataTextureSource>
     334           9 : BasicCompositor::CreateDataTextureSourceAround(DataSourceSurface* aSurface)
     335             : {
     336          18 :   RefPtr<DataTextureSource> result = new DataTextureSourceBasic(aSurface);
     337          18 :   return result.forget();
     338             : }
     339             : 
     340             : already_AddRefed<DataTextureSource>
     341           0 : BasicCompositor::CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture)
     342             : {
     343           0 :   BufferTextureHost* bufferTexture = aTexture->AsBufferTextureHost();
     344           0 :   MOZ_ASSERT(bufferTexture);
     345             : 
     346           0 :   if (!bufferTexture) {
     347           0 :     return nullptr;
     348             :   }
     349           0 :   RefPtr<DataTextureSource> result = new WrappingTextureSourceYCbCrBasic(bufferTexture);
     350           0 :   return result.forget();
     351             : }
     352             : 
     353             : bool
     354           0 : BasicCompositor::SupportsEffect(EffectTypes aEffect)
     355             : {
     356           0 :   return aEffect != EffectTypes::YCBCR && aEffect != EffectTypes::COMPONENT_ALPHA;
     357             : }
     358             : 
     359             : bool
     360          88 : BasicCompositor::SupportsLayerGeometry() const
     361             : {
     362          88 :   return gfxPrefs::BasicLayerGeometry();
     363             : }
     364             : 
     365             : static RefPtr<gfx::Path>
     366           0 : BuildPathFromPolygon(const RefPtr<DrawTarget>& aDT,
     367             :                      const gfx::Polygon& aPolygon)
     368             : {
     369           0 :   MOZ_ASSERT(!aPolygon.IsEmpty());
     370             : 
     371           0 :   RefPtr<PathBuilder> pathBuilder = aDT->CreatePathBuilder();
     372           0 :   const nsTArray<Point4D>& points = aPolygon.GetPoints();
     373             : 
     374           0 :   pathBuilder->MoveTo(points[0].As2DPoint());
     375             : 
     376           0 :   for (size_t i = 1; i < points.Length(); ++i) {
     377           0 :     pathBuilder->LineTo(points[i].As2DPoint());
     378             :   }
     379             : 
     380           0 :   pathBuilder->Close();
     381           0 :   return pathBuilder->Finish();
     382             : }
     383             : 
     384             : static void
     385           5 : DrawSurface(gfx::DrawTarget* aDest,
     386             :             const gfx::Rect& aDestRect,
     387             :             const gfx::Rect& /* aClipRect */,
     388             :             const gfx::Color& aColor,
     389             :             const gfx::DrawOptions& aOptions,
     390             :             gfx::SourceSurface* aMask,
     391             :             const gfx::Matrix* aMaskTransform)
     392             : {
     393             :   FillRectWithMask(aDest, aDestRect, aColor,
     394           5 :                    aOptions, aMask, aMaskTransform);
     395           5 : }
     396             : 
     397             : static void
     398           0 : DrawSurface(gfx::DrawTarget* aDest,
     399             :             const gfx::Polygon& aPolygon,
     400             :             const gfx::Rect& aClipRect,
     401             :             const gfx::Color& aColor,
     402             :             const gfx::DrawOptions& aOptions,
     403             :             gfx::SourceSurface* aMask,
     404             :             const gfx::Matrix* aMaskTransform)
     405             : {
     406           0 :   RefPtr<Path> path = BuildPathFromPolygon(aDest, aPolygon);
     407             :   FillPathWithMask(aDest, path, aClipRect, aColor,
     408           0 :                    aOptions, aMask, aMaskTransform);
     409           0 : }
     410             : 
     411             : static void
     412          56 : DrawTextureSurface(gfx::DrawTarget* aDest,
     413             :                    const gfx::Rect& aDestRect,
     414             :                    const gfx::Rect& /* aClipRect */,
     415             :                    gfx::SourceSurface* aSource,
     416             :                    gfx::SamplingFilter aSamplingFilter,
     417             :                    const gfx::DrawOptions& aOptions,
     418             :                    ExtendMode aExtendMode,
     419             :                    gfx::SourceSurface* aMask,
     420             :                    const gfx::Matrix* aMaskTransform,
     421             :                    const Matrix* aSurfaceTransform)
     422             : {
     423             :   FillRectWithMask(aDest, aDestRect, aSource, aSamplingFilter, aOptions,
     424          56 :                    aExtendMode, aMask, aMaskTransform, aSurfaceTransform);
     425          56 : }
     426             : 
     427             : static void
     428           0 : DrawTextureSurface(gfx::DrawTarget* aDest,
     429             :                    const gfx::Polygon& aPolygon,
     430             :                    const gfx::Rect& aClipRect,
     431             :                    gfx::SourceSurface* aSource,
     432             :                    gfx::SamplingFilter aSamplingFilter,
     433             :                    const gfx::DrawOptions& aOptions,
     434             :                    ExtendMode aExtendMode,
     435             :                    gfx::SourceSurface* aMask,
     436             :                    const gfx::Matrix* aMaskTransform,
     437             :                    const Matrix* aSurfaceTransform)
     438             : {
     439           0 :   RefPtr<Path> path = BuildPathFromPolygon(aDest, aPolygon);
     440             :   FillPathWithMask(aDest, path, aClipRect, aSource, aSamplingFilter, aOptions,
     441           0 :                    aExtendMode, aMask, aMaskTransform, aSurfaceTransform);
     442           0 : }
     443             : 
     444             : template<typename Geometry>
     445             : static void
     446          56 : DrawSurfaceWithTextureCoords(gfx::DrawTarget* aDest,
     447             :                              const Geometry& aGeometry,
     448             :                              const gfx::Rect& aDestRect,
     449             :                              gfx::SourceSurface* aSource,
     450             :                              const gfx::Rect& aTextureCoords,
     451             :                              gfx::SamplingFilter aSamplingFilter,
     452             :                              const gfx::DrawOptions& aOptions,
     453             :                              gfx::SourceSurface* aMask,
     454             :                              const gfx::Matrix* aMaskTransform)
     455             : {
     456          56 :   if (!aSource) {
     457           0 :     gfxWarning() << "DrawSurfaceWithTextureCoords problem " << gfx::hexa(aSource) << " and " << gfx::hexa(aMask);
     458           0 :     return;
     459             :   }
     460             : 
     461             :   // Convert aTextureCoords into aSource's coordinate space
     462         112 :   gfxRect sourceRect(aTextureCoords.x * aSource->GetSize().width,
     463         112 :                      aTextureCoords.y * aSource->GetSize().height,
     464         112 :                      aTextureCoords.width * aSource->GetSize().width,
     465         280 :                      aTextureCoords.height * aSource->GetSize().height);
     466             : 
     467             :   // Floating point error can accumulate above and we know our visible region
     468             :   // is integer-aligned, so round it out.
     469          56 :   sourceRect.Round();
     470             : 
     471             :   // Compute a transform that maps sourceRect to aDestRect.
     472             :   Matrix matrix =
     473             :     gfxUtils::TransformRectToRect(sourceRect,
     474         112 :                                   gfx::IntPoint::Truncate(aDestRect.x, aDestRect.y),
     475         112 :                                   gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.y),
     476         168 :                                   gfx::IntPoint::Truncate(aDestRect.XMost(), aDestRect.YMost()));
     477             : 
     478             :   // Only use REPEAT if aTextureCoords is outside (0, 0, 1, 1).
     479          56 :   gfx::Rect unitRect(0, 0, 1, 1);
     480          56 :   ExtendMode mode = unitRect.Contains(aTextureCoords) ? ExtendMode::CLAMP : ExtendMode::REPEAT;
     481             : 
     482          56 :   DrawTextureSurface(aDest, aGeometry, aDestRect, aSource, aSamplingFilter,
     483             :                      aOptions, mode, aMask, aMaskTransform, &matrix);
     484             : }
     485             : 
     486             : static void
     487          61 : SetupMask(const EffectChain& aEffectChain,
     488             :           DrawTarget* aDest,
     489             :           const IntPoint& aOffset,
     490             :           RefPtr<SourceSurface>& aMaskSurface,
     491             :           Matrix& aMaskTransform)
     492             : {
     493          61 :   if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
     494           0 :     EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
     495           0 :     aMaskSurface = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(aDest);
     496           0 :     if (!aMaskSurface) {
     497           0 :       gfxWarning() << "Invalid sourceMask effect";
     498             :     }
     499           0 :     MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
     500           0 :     aMaskTransform = effectMask->mMaskTransform.As2D();
     501           0 :     aMaskTransform.PostTranslate(-aOffset.x, -aOffset.y);
     502             :   }
     503          61 : }
     504             : 
     505             : static bool
     506           0 : AttemptVideoScale(TextureSourceBasic* aSource, const SourceSurface* aSourceMask,
     507             :                        gfx::Float aOpacity, CompositionOp aBlendMode,
     508             :                        const TexturedEffect* aTexturedEffect,
     509             :                        const Matrix& aNewTransform, const gfx::Rect& aRect,
     510             :                        const gfx::Rect& aClipRect,
     511             :                        DrawTarget* aDest, const DrawTarget* aBuffer)
     512             : {
     513             : #ifdef MOZILLA_SSE_HAVE_CPUID_DETECTION
     514           0 :   if (!mozilla::supports_ssse3())
     515           0 :       return false;
     516           0 :   if (aNewTransform.IsTranslation()) // unscaled painting should take the regular path
     517           0 :       return false;
     518           0 :   if (aNewTransform.HasNonAxisAlignedTransform() || aNewTransform.HasNegativeScaling())
     519           0 :       return false;
     520           0 :   if (aSourceMask || aOpacity != 1.0f)
     521           0 :       return false;
     522           0 :   if (aBlendMode != CompositionOp::OP_OVER && aBlendMode != CompositionOp::OP_SOURCE)
     523           0 :       return false;
     524             : 
     525           0 :   IntRect dstRect;
     526             :   // the compiler should know a lot about aNewTransform at this point
     527             :   // maybe it can do some sophisticated optimization of the following
     528           0 :   if (!aNewTransform.TransformBounds(aRect).ToIntRect(&dstRect))
     529           0 :       return false;
     530             : 
     531           0 :   IntRect clipRect;
     532           0 :   if (!aClipRect.ToIntRect(&clipRect))
     533           0 :       return false;
     534             : 
     535           0 :   if (!(aTexturedEffect->mTextureCoords == Rect(0.0f, 0.0f, 1.0f, 1.0f)))
     536           0 :       return false;
     537           0 :   if (aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16)
     538           0 :       return false;
     539             : 
     540             :   uint8_t* dstData;
     541           0 :   IntSize dstSize;
     542             :   int32_t dstStride;
     543             :   SurfaceFormat dstFormat;
     544           0 :   if (aDest->LockBits(&dstData, &dstSize, &dstStride, &dstFormat)) {
     545             :     // If we're not painting to aBuffer the clip will
     546             :     // be applied later
     547           0 :     IntRect fillRect = dstRect;
     548           0 :     if (aDest == aBuffer) {
     549             :       // we need to clip fillRect because LockBits ignores the clip on the aDest
     550           0 :       fillRect = fillRect.Intersect(clipRect);
     551             :     }
     552             : 
     553           0 :     fillRect = fillRect.Intersect(IntRect(IntPoint(0, 0), aDest->GetSize()));
     554           0 :     IntPoint offset = fillRect.TopLeft() - dstRect.TopLeft();
     555             : 
     556           0 :     RefPtr<DataSourceSurface> srcSource = aSource->GetSurface(aDest)->GetDataSurface();
     557           0 :     DataSourceSurface::ScopedMap mapSrc(srcSource, DataSourceSurface::READ);
     558             : 
     559           0 :     ssse3_scale_data((uint32_t*)mapSrc.GetData(), srcSource->GetSize().width, srcSource->GetSize().height,
     560           0 :                      mapSrc.GetStride()/4,
     561           0 :                      ((uint32_t*)dstData) + fillRect.x + (dstStride / 4) * fillRect.y, dstRect.width, dstRect.height,
     562             :                      dstStride / 4,
     563             :                      offset.x, offset.y,
     564           0 :                      fillRect.width, fillRect.height);
     565             : 
     566           0 :     aDest->ReleaseBits(dstData);
     567           0 :     return true;
     568             :   } else
     569             : #endif // MOZILLA_SSE_HAVE_CPUID_DETECTION
     570           0 :     return false;
     571             : }
     572             : 
     573             : static bool
     574           0 : AttemptVideoConvertAndScale(TextureSource* aSource, const SourceSurface* aSourceMask,
     575             :                             gfx::Float aOpacity, CompositionOp aBlendMode,
     576             :                             const TexturedEffect* aTexturedEffect,
     577             :                             const Matrix& aNewTransform, const gfx::Rect& aRect,
     578             :                             const gfx::Rect& aClipRect,
     579             :                             DrawTarget* aDest, const DrawTarget* aBuffer)
     580             : {
     581             : #if defined(XP_WIN) && defined(_M_X64)
     582             :   // libyuv does not support SIMD scaling on win 64bit. See Bug 1295927.
     583             :   return false;
     584             : #endif
     585             : 
     586           0 :   WrappingTextureSourceYCbCrBasic* wrappingSource = aSource->AsWrappingTextureSourceYCbCrBasic();
     587           0 :   if (!wrappingSource)
     588           0 :     return false;
     589             : #ifdef MOZILLA_SSE_HAVE_CPUID_DETECTION
     590           0 :   if (!mozilla::supports_ssse3()) // libyuv requests SSSE3 for fast YUV conversion.
     591           0 :     return false;
     592           0 :   if (aNewTransform.HasNonAxisAlignedTransform() || aNewTransform.HasNegativeScaling())
     593           0 :       return false;
     594           0 :   if (aSourceMask || aOpacity != 1.0f)
     595           0 :     return false;
     596           0 :   if (aBlendMode != CompositionOp::OP_OVER && aBlendMode != CompositionOp::OP_SOURCE)
     597           0 :     return false;
     598             : 
     599           0 :   IntRect dstRect;
     600             :   // the compiler should know a lot about aNewTransform at this point
     601             :   // maybe it can do some sophisticated optimization of the following
     602           0 :   if (!aNewTransform.TransformBounds(aRect).ToIntRect(&dstRect))
     603           0 :     return false;
     604             : 
     605           0 :   IntRect clipRect;
     606           0 :   if (!aClipRect.ToIntRect(&clipRect))
     607           0 :     return false;
     608             : 
     609           0 :   if (!(aTexturedEffect->mTextureCoords == Rect(0.0f, 0.0f, 1.0f, 1.0f)))
     610           0 :     return false;
     611           0 :   if (aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16)
     612           0 :     return false;
     613             : 
     614           0 :   if (aDest == aBuffer && !clipRect.Contains(dstRect))
     615           0 :     return false;
     616           0 :   if (!IntRect(IntPoint(0, 0), aDest->GetSize()).Contains(dstRect))
     617           0 :     return false;
     618             : 
     619             :   uint8_t* dstData;
     620           0 :   IntSize dstSize;
     621             :   int32_t dstStride;
     622             :   SurfaceFormat dstFormat;
     623           0 :   if (aDest->LockBits(&dstData, &dstSize, &dstStride, &dstFormat)) {
     624           0 :     wrappingSource->ConvertAndScale(dstFormat,
     625           0 :                                     dstRect.Size(),
     626           0 :                                     dstData + ptrdiff_t(dstRect.x) * BytesPerPixel(dstFormat) + ptrdiff_t(dstRect.y) * dstStride,
     627           0 :                                     dstStride);
     628           0 :     aDest->ReleaseBits(dstData);
     629           0 :     return true;
     630             :   } else
     631             : #endif // MOZILLA_SSE_HAVE_CPUID_DETECTION
     632           0 :     return false;
     633             : }
     634             : 
     635             : void
     636          61 : BasicCompositor::DrawQuad(const gfx::Rect& aRect,
     637             :                           const gfx::IntRect& aClipRect,
     638             :                           const EffectChain &aEffectChain,
     639             :                           gfx::Float aOpacity,
     640             :                           const gfx::Matrix4x4& aTransform,
     641             :                           const gfx::Rect& aVisibleRect)
     642             : {
     643             :   DrawGeometry(aRect, aRect, aClipRect, aEffectChain,
     644          61 :                aOpacity, aTransform, aVisibleRect, true);
     645          61 : }
     646             : 
     647             : void
     648           0 : BasicCompositor::DrawPolygon(const gfx::Polygon& aPolygon,
     649             :                              const gfx::Rect& aRect,
     650             :                              const gfx::IntRect& aClipRect,
     651             :                              const EffectChain& aEffectChain,
     652             :                              gfx::Float aOpacity,
     653             :                              const gfx::Matrix4x4& aTransform,
     654             :                              const gfx::Rect& aVisibleRect)
     655             : {
     656             :   DrawGeometry(aPolygon, aRect, aClipRect, aEffectChain,
     657           0 :                aOpacity, aTransform, aVisibleRect, false);
     658           0 : }
     659             : 
     660             : 
     661             : template<typename Geometry>
     662             : void
     663          61 : BasicCompositor::DrawGeometry(const Geometry& aGeometry,
     664             :                               const gfx::Rect& aRect,
     665             :                               const gfx::IntRect& aClipRect,
     666             :                               const EffectChain& aEffectChain,
     667             :                               gfx::Float aOpacity,
     668             :                               const gfx::Matrix4x4& aTransform,
     669             :                               const gfx::Rect& aVisibleRect,
     670             :                               const bool aEnableAA)
     671             : {
     672         122 :   RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;
     673             : 
     674             :   // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
     675             :   // |dest| is a temporary surface.
     676         122 :   RefPtr<DrawTarget> dest = buffer;
     677             : 
     678         122 :   AutoRestoreTransform autoRestoreTransform(dest);
     679             : 
     680          61 :   Matrix newTransform;
     681          61 :   Rect transformBounds;
     682          61 :   Matrix4x4 new3DTransform;
     683          61 :   IntPoint offset = mRenderTarget->GetOrigin();
     684             : 
     685          61 :   if (aTransform.Is2D()) {
     686          61 :     newTransform = aTransform.As2D();
     687             :   } else {
     688             :     // Create a temporary surface for the transform.
     689           0 :     dest = Factory::CreateDrawTarget(gfxVars::ContentBackend(), RoundedOut(aRect).Size(), SurfaceFormat::B8G8R8A8);
     690           0 :     if (!dest) {
     691           0 :       return;
     692             :     }
     693             : 
     694           0 :     dest->SetTransform(Matrix::Translation(-aRect.x, -aRect.y));
     695             : 
     696             :     // Get the bounds post-transform.
     697           0 :     transformBounds = aTransform.TransformAndClipBounds(aRect, Rect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));
     698           0 :     transformBounds.RoundOut();
     699             : 
     700           0 :     if (transformBounds.IsEmpty()) {
     701           0 :       return;
     702             :     }
     703             : 
     704           0 :     newTransform = Matrix();
     705             : 
     706             :     // When we apply the 3D transformation, we do it against a temporary
     707             :     // surface, so undo the coordinate offset.
     708           0 :     new3DTransform = aTransform;
     709           0 :     new3DTransform.PreTranslate(aRect.x, aRect.y, 0);
     710             :   }
     711             : 
     712             :   // XXX the transform is probably just an integer offset so this whole
     713             :   // business here is a bit silly.
     714          61 :   Rect transformedClipRect = buffer->GetTransform().TransformBounds(Rect(aClipRect));
     715             : 
     716          61 :   buffer->PushClipRect(Rect(aClipRect));
     717             : 
     718          61 :   newTransform.PostTranslate(-offset.x, -offset.y);
     719          61 :   buffer->SetTransform(newTransform);
     720             : 
     721         122 :   RefPtr<SourceSurface> sourceMask;
     722          61 :   Matrix maskTransform;
     723          61 :   if (aTransform.Is2D()) {
     724          61 :     SetupMask(aEffectChain, dest, offset, sourceMask, maskTransform);
     725             :   }
     726             : 
     727          61 :   CompositionOp blendMode = CompositionOp::OP_OVER;
     728          61 :   if (Effect* effect = aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()) {
     729           0 :     blendMode = static_cast<EffectBlendMode*>(effect)->mBlendMode;
     730             :   }
     731             : 
     732             :   const AntialiasMode aaMode =
     733          61 :     aEnableAA ? AntialiasMode::DEFAULT : AntialiasMode::NONE;
     734             : 
     735          61 :   DrawOptions drawOptions(aOpacity, blendMode, aaMode);
     736             : 
     737          61 :   switch (aEffectChain.mPrimaryEffect->mType) {
     738             :     case EffectTypes::SOLID_COLOR: {
     739             :       EffectSolidColor* effectSolidColor =
     740           5 :         static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
     741             : 
     742           5 :       bool unboundedOp = !IsOperatorBoundByMask(blendMode);
     743           5 :       if (unboundedOp) {
     744           0 :         dest->PushClipRect(aRect);
     745             :       }
     746             : 
     747           5 :       DrawSurface(dest, aGeometry, aRect, effectSolidColor->mColor,
     748             :                   drawOptions, sourceMask, &maskTransform);
     749             : 
     750           5 :       if (unboundedOp) {
     751           0 :         dest->PopClip();
     752             :       }
     753           5 :       break;
     754             :     }
     755             :     case EffectTypes::RGB: {
     756             :       TexturedEffect* texturedEffect =
     757          56 :           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
     758          56 :       TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();
     759             : 
     760          56 :       if (source && texturedEffect->mPremultiplied) {
     761             :         // we have a fast path for video here
     762         112 :         if (source->mFromYCBCR &&
     763           0 :             AttemptVideoConvertAndScale(texturedEffect->mTexture, sourceMask, aOpacity, blendMode,
     764             :                                         texturedEffect,
     765             :                                         newTransform, aRect, transformedClipRect,
     766             :                                         dest, buffer)) {
     767             :           // we succeeded in convert and scaling
     768          56 :         } else if (source->mFromYCBCR &&
     769           0 :                    !source->GetSurface(dest)) {
     770           0 :           gfxWarning() << "Failed to get YCbCr to rgb surface.";
     771          56 :         } else if (source->mFromYCBCR &&
     772           0 :             AttemptVideoScale(source, sourceMask, aOpacity, blendMode,
     773             :                               texturedEffect,
     774             :                               newTransform, aRect, transformedClipRect,
     775             :                               dest, buffer)) {
     776             :           // we succeeded in scaling
     777             :         } else {
     778         112 :           DrawSurfaceWithTextureCoords(dest, aGeometry, aRect,
     779          56 :                                        source->GetSurface(dest),
     780             :                                        texturedEffect->mTextureCoords,
     781             :                                        texturedEffect->mSamplingFilter,
     782             :                                        drawOptions,
     783             :                                        sourceMask, &maskTransform);
     784             :         }
     785           0 :       } else if (source) {
     786           0 :         SourceSurface* srcSurf = source->GetSurface(dest);
     787           0 :         if (srcSurf) {
     788           0 :           RefPtr<DataSourceSurface> srcData = srcSurf->GetDataSurface();
     789             : 
     790             :           // Yes, we re-create the premultiplied data every time.
     791             :           // This might be better with a cache, eventually.
     792           0 :           RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData);
     793             : 
     794           0 :           DrawSurfaceWithTextureCoords(dest, aGeometry, aRect,
     795             :                                        premultData,
     796             :                                        texturedEffect->mTextureCoords,
     797             :                                        texturedEffect->mSamplingFilter,
     798             :                                        drawOptions,
     799             :                                        sourceMask, &maskTransform);
     800             :         }
     801             :       } else {
     802           0 :         gfxDevCrash(LogReason::IncompatibleBasicTexturedEffect) << "Bad for basic with " << texturedEffect->mTexture->Name() << " and " << gfx::hexa(sourceMask);
     803             :       }
     804             : 
     805          56 :       break;
     806             :     }
     807             :     case EffectTypes::YCBCR: {
     808           0 :       MOZ_CRASH("Can't (easily) support component alpha with BasicCompositor!");
     809             :       break;
     810             :     }
     811             :     case EffectTypes::RENDER_TARGET: {
     812             :       EffectRenderTarget* effectRenderTarget =
     813           0 :         static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
     814             :       RefPtr<BasicCompositingRenderTarget> surface
     815           0 :         = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get());
     816           0 :       RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot();
     817             : 
     818           0 :       DrawSurfaceWithTextureCoords(dest, aGeometry, aRect,
     819             :                                    sourceSurf,
     820             :                                    effectRenderTarget->mTextureCoords,
     821             :                                    effectRenderTarget->mSamplingFilter,
     822             :                                    drawOptions,
     823             :                                    sourceMask, &maskTransform);
     824           0 :       break;
     825             :     }
     826             :     case EffectTypes::COMPONENT_ALPHA: {
     827           0 :       MOZ_CRASH("Can't (easily) support component alpha with BasicCompositor!");
     828             :       break;
     829             :     }
     830             :     default: {
     831           0 :       MOZ_CRASH("Invalid effect type!");
     832             :       break;
     833             :     }
     834             :   }
     835             : 
     836          61 :   if (!aTransform.Is2D()) {
     837           0 :     dest->Flush();
     838             : 
     839           0 :     RefPtr<SourceSurface> destSnapshot = dest->Snapshot();
     840             : 
     841           0 :     SetupMask(aEffectChain, buffer, offset, sourceMask, maskTransform);
     842             : 
     843           0 :     if (sourceMask) {
     844             :       RefPtr<DrawTarget> transformDT =
     845           0 :         dest->CreateSimilarDrawTarget(IntSize::Truncate(transformBounds.width, transformBounds.height),
     846           0 :                                       SurfaceFormat::B8G8R8A8);
     847           0 :       new3DTransform.PostTranslate(-transformBounds.x, -transformBounds.y, 0);
     848           0 :       if (transformDT &&
     849           0 :           transformDT->Draw3DTransformedSurface(destSnapshot, new3DTransform)) {
     850           0 :         RefPtr<SourceSurface> transformSnapshot = transformDT->Snapshot();
     851             : 
     852             :         // Transform the source by it's normal transform, and then the inverse
     853             :         // of the mask transform so that it's in the mask's untransformed
     854             :         // coordinate space.
     855           0 :         Matrix sourceTransform = newTransform;
     856           0 :         sourceTransform.PostTranslate(transformBounds.TopLeft());
     857             : 
     858           0 :         Matrix inverseMask = maskTransform;
     859           0 :         inverseMask.Invert();
     860             : 
     861           0 :         sourceTransform *= inverseMask;
     862             : 
     863           0 :         SurfacePattern source(transformSnapshot, ExtendMode::CLAMP, sourceTransform);
     864             : 
     865           0 :         buffer->PushClipRect(transformBounds);
     866             : 
     867             :         // Mask in the untransformed coordinate space, and then transform
     868             :         // by the mask transform to put the result back into destination
     869             :         // coords.
     870           0 :         buffer->SetTransform(maskTransform);
     871           0 :         buffer->MaskSurface(source, sourceMask, Point(0, 0));
     872             : 
     873           0 :         buffer->PopClip();
     874             :       }
     875             :     } else {
     876           0 :       buffer->Draw3DTransformedSurface(destSnapshot, new3DTransform);
     877             :     }
     878             :   }
     879             : 
     880          61 :   buffer->PopClip();
     881             : }
     882             : 
     883             : void
     884           0 : BasicCompositor::ClearRect(const gfx::Rect& aRect)
     885             : {
     886           0 :   mRenderTarget->mDrawTarget->ClearRect(aRect);
     887           0 : }
     888             : 
     889             : void
     890          27 : BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
     891             :                             const gfx::IntRect *aClipRectIn,
     892             :                             const gfx::IntRect& aRenderBounds,
     893             :                             const nsIntRegion& aOpaqueRegion,
     894             :                             gfx::IntRect *aClipRectOut /* = nullptr */,
     895             :                             gfx::IntRect *aRenderBoundsOut /* = nullptr */)
     896             : {
     897          27 :   if (mIsPendingEndRemoteDrawing) {
     898             :     // Force to end previous remote drawing.
     899           0 :     TryToEndRemoteDrawing(/* aForceToEnd */ true);
     900           0 :     MOZ_ASSERT(!mIsPendingEndRemoteDrawing);
     901             :   }
     902             : 
     903          27 :   LayoutDeviceIntRect intRect(LayoutDeviceIntPoint(), mWidget->GetClientSize());
     904          27 :   IntRect rect = IntRect(0, 0, intRect.width, intRect.height);
     905             : 
     906          54 :   LayoutDeviceIntRegion invalidRegionSafe;
     907             :   // Sometimes the invalid region is larger than we want to draw.
     908             :   invalidRegionSafe.And(
     909          27 :       LayoutDeviceIntRegion::FromUnknownRegion(aInvalidRegion), intRect);
     910             : 
     911          27 :   mInvalidRegion = invalidRegionSafe;
     912          27 :   mInvalidRect = mInvalidRegion.GetBounds();
     913             : 
     914          27 :   if (aRenderBoundsOut) {
     915          27 :     *aRenderBoundsOut = IntRect();
     916             :   }
     917             : 
     918          27 :   BufferMode bufferMode = BufferMode::BUFFERED;
     919          27 :   if (mTarget) {
     920             :     // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy
     921             :     // placeholder so that CreateRenderTarget() works. This is only used to create a new buffered
     922             :     // draw target that we composite into, then copy the results the destination.
     923           0 :     mDrawTarget = mTarget;
     924           0 :     bufferMode = BufferMode::BUFFER_NONE;
     925             :   } else {
     926             :     // StartRemoteDrawingInRegion can mutate mInvalidRegion.
     927          27 :     mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion, &bufferMode);
     928          27 :     if (!mDrawTarget) {
     929           0 :       return;
     930             :     }
     931          27 :     mInvalidRect = mInvalidRegion.GetBounds();
     932          27 :     if (mInvalidRect.IsEmpty()) {
     933           0 :       mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
     934           0 :       return;
     935             :     }
     936             :   }
     937             : 
     938          27 :   if (!mDrawTarget || mInvalidRect.IsEmpty()) {
     939           0 :     return;
     940             :   }
     941             : 
     942          27 :   LayoutDeviceIntRect clearRect;
     943          27 :   if (!aOpaqueRegion.IsEmpty()) {
     944          54 :     LayoutDeviceIntRegion clearRegion = mInvalidRegion;
     945          27 :     clearRegion.SubOut(LayoutDeviceIntRegion::FromUnknownRegion(aOpaqueRegion));
     946          27 :     clearRect = clearRegion.GetBounds();
     947             :   } else {
     948           0 :     clearRect = mInvalidRect;
     949             :   }
     950             : 
     951             :   // Prevent CreateRenderTargetForWindow from clearing unwanted area.
     952          27 :   gfxUtils::ClipToRegion(mDrawTarget,
     953          54 :                          mInvalidRegion.ToUnknownRegion());
     954             : 
     955             :   // Setup an intermediate render target to buffer all compositing. We will
     956             :   // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
     957             :   RefPtr<CompositingRenderTarget> target =
     958          54 :     CreateRenderTargetForWindow(mInvalidRect,
     959             :                                 clearRect,
     960          81 :                                 bufferMode);
     961             : 
     962          27 :   mDrawTarget->PopClip();
     963             : 
     964          27 :   if (!target) {
     965           0 :     if (!mTarget) {
     966           0 :       mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
     967             :     }
     968           0 :     return;
     969             :   }
     970          27 :   SetRenderTarget(target);
     971             : 
     972             :   // We only allocate a surface sized to the invalidated region, so we need to
     973             :   // translate future coordinates.
     974          27 :   mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-mRenderTarget->GetOrigin()));
     975             : 
     976          27 :   gfxUtils::ClipToRegion(mRenderTarget->mDrawTarget,
     977          54 :                          mInvalidRegion.ToUnknownRegion());
     978             : 
     979          27 :   if (aRenderBoundsOut) {
     980          27 :     *aRenderBoundsOut = rect;
     981             :   }
     982             : 
     983          27 :   if (aClipRectIn) {
     984           0 :     mRenderTarget->mDrawTarget->PushClipRect(Rect(*aClipRectIn));
     985             :   } else {
     986          27 :     mRenderTarget->mDrawTarget->PushClipRect(Rect(rect));
     987          27 :     if (aClipRectOut) {
     988          27 :       *aClipRectOut = rect;
     989             :     }
     990             :   }
     991             : }
     992             : 
     993             : void
     994          27 : BasicCompositor::EndFrame()
     995             : {
     996          27 :   Compositor::EndFrame();
     997             : 
     998             :   // Pop aClipRectIn/bounds rect
     999          27 :   mRenderTarget->mDrawTarget->PopClip();
    1000             : 
    1001          27 :   if (gfxPrefs::WidgetUpdateFlashing()) {
    1002           0 :     float r = float(rand()) / RAND_MAX;
    1003           0 :     float g = float(rand()) / RAND_MAX;
    1004           0 :     float b = float(rand()) / RAND_MAX;
    1005             :     // We're still clipped to mInvalidRegion, so just fill the bounds.
    1006           0 :     mRenderTarget->mDrawTarget->FillRect(
    1007           0 :       IntRectToRect(mInvalidRegion.GetBounds()).ToUnknownRect(),
    1008           0 :       ColorPattern(Color(r, g, b, 0.2f)));
    1009             :   }
    1010             : 
    1011             :   // Pop aInvalidregion
    1012          27 :   mRenderTarget->mDrawTarget->PopClip();
    1013             : 
    1014          27 :   TryToEndRemoteDrawing();
    1015          27 : }
    1016             : 
    1017             : void
    1018          27 : BasicCompositor::TryToEndRemoteDrawing(bool aForceToEnd)
    1019             : {
    1020          27 :   if (mIsDestroyed || !mRenderTarget) {
    1021           0 :     return;
    1022             :   }
    1023             : 
    1024             :   // It it is not a good timing for EndRemoteDrawing, defter to call it.
    1025          27 :   if (!aForceToEnd && !mTarget && NeedsToDeferEndRemoteDrawing()) {
    1026           0 :     mIsPendingEndRemoteDrawing = true;
    1027             : 
    1028           0 :     const uint32_t retryMs = 2;
    1029           0 :     RefPtr<BasicCompositor> self = this;
    1030             :     RefPtr<Runnable> runnable =
    1031           0 :       NS_NewRunnableFunction("layers::BasicCompositor::TryToEndRemoteDrawing",
    1032           0 :                              [self]() { self->TryToEndRemoteDrawing(); });
    1033           0 :     MessageLoop::current()->PostDelayedTask(runnable.forget(), retryMs);
    1034           0 :     return;
    1035             :   }
    1036             : 
    1037          27 :   if (mRenderTarget->mDrawTarget != mDrawTarget) {
    1038             :     // Note: Most platforms require us to buffer drawing to the widget surface.
    1039             :     // That's why we don't draw to mDrawTarget directly.
    1040           0 :     RefPtr<SourceSurface> source;
    1041           0 :     if (mRenderTarget->mDrawTarget != mDrawTarget) {
    1042           0 :       source = mWidget->EndBackBufferDrawing();
    1043             :     } else {
    1044           0 :       source = mRenderTarget->mDrawTarget->Snapshot();
    1045             :     }
    1046           0 :     RefPtr<DrawTarget> dest(mTarget ? mTarget : mDrawTarget);
    1047             : 
    1048           0 :     nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint();
    1049             : 
    1050             :     // The source DrawTarget is clipped to the invalidation region, so we have
    1051             :     // to copy the individual rectangles in the region or else we'll draw blank
    1052             :     // pixels.
    1053           0 :     for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
    1054           0 :       const LayoutDeviceIntRect& r = iter.Get();
    1055           0 :       dest->CopySurface(source,
    1056           0 :                         IntRect(r.x, r.y, r.width, r.height) - mRenderTarget->GetOrigin(),
    1057           0 :                         IntPoint(r.x, r.y) - offset);
    1058             :     }
    1059             :   }
    1060             : 
    1061          27 :   if (aForceToEnd || !mTarget) {
    1062          27 :     mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
    1063             :   }
    1064             : 
    1065          27 :   mDrawTarget = nullptr;
    1066          27 :   mRenderTarget = nullptr;
    1067          27 :   mIsPendingEndRemoteDrawing = false;
    1068             : }
    1069             : 
    1070             : bool
    1071          27 : BasicCompositor::NeedsToDeferEndRemoteDrawing()
    1072             : {
    1073          27 :   MOZ_ASSERT(mDrawTarget);
    1074          27 :   MOZ_ASSERT(mRenderTarget);
    1075             : 
    1076          27 :   if (mTarget || mRenderTarget->mDrawTarget == mDrawTarget) {
    1077          27 :     return false;
    1078             :   }
    1079             : 
    1080           0 :   return mWidget->NeedsToDeferEndRemoteDrawing();
    1081             : }
    1082             : 
    1083             : void
    1084           0 : BasicCompositor::FinishPendingComposite()
    1085             : {
    1086           0 :   TryToEndRemoteDrawing(/* aForceToEnd */ true);
    1087           0 : }
    1088             : 
    1089             : } // namespace layers
    1090             : } // namespace mozilla

Generated by: LCOV version 1.13