Coverage Report

Created: 2018-09-25 14:53

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