Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/RotatedBuffer.h
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
#ifndef ROTATEDBUFFER_H_
8
#define ROTATEDBUFFER_H_
9
10
#include "gfxTypes.h"
11
#include <stdint.h>                     // for uint32_t
12
#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
13
#include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed
14
#include "mozilla/gfx/2D.h"             // for DrawTarget, etc
15
#include "mozilla/gfx/MatrixFwd.h"      // for Matrix
16
#include "mozilla/layers/TextureClient.h" // for TextureClient
17
#include "mozilla/mozalloc.h"           // for operator delete
18
#include "nsCOMPtr.h"                   // for already_AddRefed
19
#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
20
#include "nsRegion.h"                   // for nsIntRegion
21
#include "LayersTypes.h"
22
23
namespace mozilla {
24
namespace layers {
25
26
class PaintedLayer;
27
class ContentClient;
28
29
// Mixin class for classes which need logic for loaning out a draw target.
30
// See comments on BorrowDrawTargetForQuadrantUpdate.
31
class BorrowDrawTarget
32
{
33
public:
34
  void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
35
36
protected:
37
  // The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
38
  // be used, we just keep a reference to ensure it is kept alive and so we can
39
  // correctly restore state when it is returned.
40
  RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
41
  gfx::Matrix mLoanedTransform;
42
};
43
44
/**
45
 * This is a cairo/Thebes surface, but with a literal twist. Scrolling
46
 * causes the layer's visible region to move. We want to keep
47
 * reusing the same surface if the region size hasn't changed, but we don't
48
 * want to keep moving the contents of the surface around in memory. So
49
 * we use a trick.
50
 * Consider just the vertical case, and suppose the buffer is H pixels
51
 * high and we're scrolling down by N pixels. Instead of copying the
52
 * buffer contents up by N pixels, we leave the buffer contents in place,
53
 * and paint content rows H to H+N-1 into rows 0 to N-1 of the buffer.
54
 * Then we can refresh the screen by painting rows N to H-1 of the buffer
55
 * at row 0 on the screen, and then painting rows 0 to N-1 of the buffer
56
 * at row H-N on the screen.
57
 * mBufferRotation.y would be N in this example.
58
 */
59
class RotatedBuffer : public BorrowDrawTarget
60
{
61
public:
62
  typedef gfxContentType ContentType;
63
64
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RotatedBuffer)
65
66
  RotatedBuffer(const gfx::IntRect& aBufferRect,
67
                const gfx::IntPoint& aBufferRotation)
68
    : mCapture(nullptr)
69
    , mBufferRect(aBufferRect)
70
    , mBufferRotation(aBufferRotation)
71
    , mDidSelfCopy(false)
72
0
  { }
73
  RotatedBuffer()
74
    : mCapture(nullptr)
75
    , mDidSelfCopy(false)
76
  { }
77
78
  /**
79
   * Initializes the rotated buffer to begin capturing all drawing performed
80
   * on it, to be eventually replayed. Callers must call EndCapture, or
81
   * FlushCapture before the rotated buffer is destroyed.
82
   */
83
  void BeginCapture();
84
85
  /**
86
   * Finishes a capture and returns it. The capture must be replayed to the
87
   * buffer before it is presented or it will contain invalid contents.
88
   */
89
  RefPtr<gfx::DrawTargetCapture> EndCapture();
90
91
  /**
92
   * Returns whether the RotatedBuffer is currently capturing all drawing
93
   * performed on it, to be eventually replayed.
94
   */
95
  bool IsCapturing() const
96
  {
97
    return !!mCapture;
98
  }
99
100
  /**
101
   * Draws the contents of this rotated buffer into the specified draw target.
102
   * It is the callers repsonsibility to ensure aTarget is flushed after calling
103
   * this method.
104
   */
105
  void DrawBufferWithRotation(gfx::DrawTarget* aTarget,
106
                              float aOpacity = 1.0,
107
                              gfx::CompositionOp aOperator = gfx::CompositionOp::OP_OVER,
108
                              gfx::SourceSurface* aMask = nullptr,
109
                              const gfx::Matrix* aMaskTransform = nullptr) const;
110
111
  /**
112
   * Complete the drawing operation. The region to draw must have been
113
   * drawn before this is called. The contents of the buffer are drawn
114
   * to aTarget.
115
   */
116
  void DrawTo(PaintedLayer* aLayer,
117
              gfx::DrawTarget* aTarget,
118
              float aOpacity,
119
              gfx::CompositionOp aOp,
120
              gfx::SourceSurface* aMask,
121
              const gfx::Matrix* aMaskTransform);
122
123
  /**
124
   * Update the specified region of this rotated buffer with the contents
125
   * of a source rotated buffer.
126
   */
127
  void UpdateDestinationFrom(const RotatedBuffer& aSource,
128
                             const gfx::IntRect& aUpdateRect);
129
130
  /**
131
   * A draw iterator is used to keep track of which quadrant of a rotated
132
   * buffer and region of that quadrant is being updated.
133
   */
134
  struct DrawIterator {
135
    friend class RotatedBuffer;
136
    DrawIterator()
137
      : mCount(0)
138
0
    {}
139
140
    nsIntRegion mDrawRegion;
141
142
  private:
143
    uint32_t mCount;
144
  };
145
146
  /**
147
   * Get a draw target at the specified resolution for updating |aBounds|,
148
   * which must be contained within a single quadrant.
149
   *
150
   * The result should only be held temporarily by the caller (it will be kept
151
   * alive by this). Once used it should be returned using ReturnDrawTarget.
152
   * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
153
   * first calling ReturnDrawTarget.
154
   *
155
   * ReturnDrawTarget will by default restore the transform on the draw target.
156
   * But it is the callers responsibility to restore the clip.
157
   * The caller should flush the draw target, if necessary.
158
   * If aSetTransform is false, the required transform will be set in aOutTransform.
159
   */
160
  gfx::DrawTarget*
161
  BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
162
                                    DrawIterator* aIter);
163
164
  struct Parameters {
165
    Parameters(const gfx::IntRect& aBufferRect,
166
               const gfx::IntPoint& aBufferRotation)
167
      : mBufferRect(aBufferRect)
168
      , mBufferRotation(aBufferRotation)
169
      , mDidSelfCopy(false)
170
0
    {
171
0
    }
172
173
    bool IsRotated() const;
174
    bool RectWrapsBuffer(const gfx::IntRect& aRect) const;
175
176
    void SetUnrotated();
177
178
    gfx::IntRect  mBufferRect;
179
    gfx::IntPoint mBufferRotation;
180
    bool mDidSelfCopy;
181
  };
182
183
  /**
184
   * Returns the new buffer parameters for rotating to a
185
   * destination buffer rect.
186
   */
187
  Parameters AdjustedParameters(const gfx::IntRect& aDestBufferRect) const;
188
189
  /**
190
   * Unrotates the pixels of the rotated buffer for the specified
191
   * new buffer parameters.
192
   */
193
  bool UnrotateBufferTo(const Parameters& aParameters);
194
195
  void SetParameters(const Parameters& aParameters);
196
197
  /**
198
   * |BufferRect()| is the rect of device pixels that this
199
   * RotatedBuffer covers.  That is what DrawBufferWithRotation()
200
   * will paint when it's called.
201
   */
202
0
  const gfx::IntRect& BufferRect() const { return mBufferRect; }
203
0
  const gfx::IntPoint& BufferRotation() const { return mBufferRotation; }
204
205
  /**
206
   * Overrides the current buffer rect with the specified rect.
207
   * Do not do this unless you know what you're doing.
208
   */
209
0
  void SetBufferRect(const gfx::IntRect& aBufferRect) {
210
0
    mBufferRect = aBufferRect;
211
0
  }
212
213
  /**
214
   * Overrides the current buffer rotation with the specified point.
215
   * Do not do this unless you know what you're doing.
216
   */
217
0
  void SetBufferRotation(const gfx::IntPoint& aBufferRotation) {
218
0
    mBufferRotation = aBufferRotation;
219
0
  }
220
221
  /**
222
   * Returns whether this buffer did a self copy when adjusting to
223
   * a new buffer rect. This is only used externally for syncing
224
   * rotated buffers.
225
   */
226
0
  bool DidSelfCopy() const { return mDidSelfCopy; }
227
228
  /**
229
   * Clears the self copy flag.
230
   */
231
0
  void ClearDidSelfCopy() { mDidSelfCopy = false; }
232
233
  /**
234
   * Gets the content type for this buffer.
235
   */
236
  ContentType GetContentType() const;
237
238
  virtual bool IsLocked() = 0;
239
  virtual bool Lock(OpenMode aMode) = 0;
240
  virtual void Unlock() = 0;
241
242
  virtual bool HaveBuffer() const = 0;
243
  virtual bool HaveBufferOnWhite() const = 0;
244
245
  virtual gfx::SurfaceFormat GetFormat() const = 0;
246
247
  virtual already_AddRefed<gfx::SourceSurface> GetBufferSource() const
248
0
  {
249
0
    return GetBufferTarget()->Snapshot();
250
0
  }
251
  virtual gfx::DrawTarget* GetBufferTarget() const = 0;
252
253
0
  virtual TextureClient* GetClient() const {
254
0
    return nullptr;
255
0
  }
256
0
  virtual TextureClient* GetClientOnWhite() const {
257
0
    return nullptr;
258
0
  }
259
260
protected:
261
  virtual ~RotatedBuffer()
262
0
  {
263
0
    MOZ_ASSERT(!mCapture);
264
0
  }
265
266
  enum XSide {
267
    LEFT, RIGHT
268
  };
269
  enum YSide {
270
    TOP, BOTTOM
271
  };
272
  gfx::IntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
273
274
  gfx::Rect GetSourceRectangle(XSide aXSide, YSide aYSide) const;
275
276
  gfx::DrawTarget* GetDrawTarget() const
277
0
  {
278
0
    if (mCapture) {
279
0
      return mCapture;
280
0
    }
281
0
    return GetBufferTarget();
282
0
  }
283
284
  /*
285
   * If aMask is non-null, then it is used as an alpha mask for rendering this
286
   * buffer. aMaskTransform must be non-null if aMask is non-null, and is used
287
   * to adjust the coordinate space of the mask.
288
   */
289
  void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
290
                          float aOpacity,
291
                          gfx::CompositionOp aOperator,
292
                          gfx::SourceSurface* aMask,
293
                          const gfx::Matrix* aMaskTransform) const;
294
295
  RefPtr<gfx::DrawTargetCapture> mCapture;
296
297
  /** The area of the PaintedLayer that is covered by the buffer as a whole */
298
  gfx::IntRect  mBufferRect;
299
  /**
300
   * The x and y rotation of the buffer. Conceptually the buffer
301
   * has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
302
   * is tiled to fill the plane, and the result is clipped to mBufferRect.
303
   * So the pixel at mBufferRotation within the buffer is what gets painted at
304
   * mBufferRect.TopLeft().
305
   * This is "rotation" in the sense of rotating items in a linear buffer,
306
   * where items falling off the end of the buffer are returned to the
307
   * buffer at the other end, not 2D rotation!
308
   */
309
  gfx::IntPoint mBufferRotation;
310
  /**
311
   * When this is true it means that all pixels have moved inside the buffer.
312
   * It's not possible to sync with another buffer without a full copy.
313
   */
314
  bool          mDidSelfCopy;
315
};
316
317
/**
318
 * RemoteRotatedBuffer is a rotated buffer that is backed by texture
319
 * clients. Before you use this class you must successfully lock it with
320
 * an appropriate open mode, and then also unlock it when you're finished.
321
 * RemoteRotatedBuffer is used by ContentClientSingleBuffered and
322
 * ContentClientDoubleBuffered for the OMTC code path.
323
 */
324
class RemoteRotatedBuffer : public RotatedBuffer
325
{
326
public:
327
  RemoteRotatedBuffer(TextureClient* aClient, TextureClient* aClientOnWhite,
328
                      const gfx::IntRect& aBufferRect,
329
                      const gfx::IntPoint& aBufferRotation)
330
    : RotatedBuffer(aBufferRect, aBufferRotation)
331
    , mClient(aClient)
332
    , mClientOnWhite(aClientOnWhite)
333
0
  { }
334
335
  virtual bool IsLocked() override;
336
  virtual bool Lock(OpenMode aMode) override;
337
  virtual void Unlock() override;
338
339
0
  virtual bool HaveBuffer() const override { return !!mClient; }
340
0
  virtual bool HaveBufferOnWhite() const override { return !!mClientOnWhite; }
341
342
  virtual gfx::SurfaceFormat GetFormat() const override;
343
344
  virtual gfx::DrawTarget* GetBufferTarget() const override;
345
346
0
  virtual TextureClient* GetClient() const override { return mClient; }
347
0
  virtual TextureClient* GetClientOnWhite() const override { return mClientOnWhite; }
348
349
  void SyncWithObject(SyncObjectClient* aSyncObject);
350
  void Clear();
351
352
private:
353
  RemoteRotatedBuffer(TextureClient* aClient, TextureClient* aClientOnWhite,
354
                      gfx::DrawTarget* aTarget, gfx::DrawTarget* aTargetOnWhite, gfx::DrawTarget* aTargetDual,
355
                      const gfx::IntRect& aBufferRect,
356
                      const gfx::IntPoint& aBufferRotation)
357
    : RotatedBuffer(aBufferRect, aBufferRotation)
358
    , mClient(aClient)
359
    , mClientOnWhite(aClientOnWhite)
360
    , mTarget(aTarget)
361
    , mTargetOnWhite(aTargetOnWhite)
362
    , mTargetDual(aTargetDual)
363
  { }
364
365
  RefPtr<TextureClient> mClient;
366
  RefPtr<TextureClient> mClientOnWhite;
367
368
  RefPtr<gfx::DrawTarget> mTarget;
369
  RefPtr<gfx::DrawTarget> mTargetOnWhite;
370
  RefPtr<gfx::DrawTarget> mTargetDual;
371
};
372
373
/**
374
 * DrawTargetRotatedBuffer is a rotated buffer that is backed by draw targets,
375
 * and is used by ContentClientBasic for the on-mtc code path.
376
 */
377
class DrawTargetRotatedBuffer : public RotatedBuffer
378
{
379
public:
380
  DrawTargetRotatedBuffer(gfx::DrawTarget* aTarget, gfx::DrawTarget* aTargetOnWhite,
381
                          const gfx::IntRect& aBufferRect,
382
                          const gfx::IntPoint& aBufferRotation)
383
    : RotatedBuffer(aBufferRect, aBufferRotation)
384
    , mTarget(aTarget)
385
    , mTargetOnWhite(aTargetOnWhite)
386
0
  {
387
0
    if (mTargetOnWhite) {
388
0
      mTargetDual = gfx::Factory::CreateDualDrawTarget(mTarget, mTargetOnWhite);
389
0
    } else {
390
0
      mTargetDual = mTarget;
391
0
    }
392
0
  }
393
394
0
  virtual bool IsLocked() override { return false; }
395
0
  virtual bool Lock(OpenMode aMode) override { return true; }
396
0
  virtual void Unlock() override {}
397
398
0
  virtual bool HaveBuffer() const override { return !!mTargetDual; }
399
0
  virtual bool HaveBufferOnWhite() const override { return !!mTargetOnWhite; }
400
401
  virtual gfx::SurfaceFormat GetFormat() const override;
402
403
  virtual gfx::DrawTarget* GetBufferTarget() const override;
404
405
private:
406
  RefPtr<gfx::DrawTarget> mTarget;
407
  RefPtr<gfx::DrawTarget> mTargetOnWhite;
408
  RefPtr<gfx::DrawTarget> mTargetDual;
409
};
410
411
/**
412
 * SourceRotatedBuffer is a rotated buffer that is backed by source surfaces,
413
 * and may only be used to draw into other buffers or be read directly.
414
 */
415
class SourceRotatedBuffer : public RotatedBuffer
416
{
417
public:
418
  SourceRotatedBuffer(gfx::SourceSurface* aSource, gfx::SourceSurface* aSourceOnWhite,
419
                      const gfx::IntRect& aBufferRect,
420
                      const gfx::IntPoint& aBufferRotation)
421
    : RotatedBuffer(aBufferRect, aBufferRotation)
422
    , mSource(aSource)
423
    , mSourceOnWhite(aSourceOnWhite)
424
0
  {
425
0
    mSourceDual = gfx::Factory::CreateDualSourceSurface(mSource, mSourceOnWhite);
426
0
  }
427
428
0
  virtual bool IsLocked() override { return false; }
429
0
  virtual bool Lock(OpenMode aMode) override { return false; }
430
0
  virtual void Unlock() override {}
431
432
  virtual already_AddRefed<gfx::SourceSurface> GetBufferSource() const override;
433
434
  virtual gfx::SurfaceFormat GetFormat() const override;
435
436
0
  virtual bool HaveBuffer() const override { return !!mSourceDual; }
437
0
  virtual bool HaveBufferOnWhite() const override { return !!mSourceOnWhite; }
438
439
0
  virtual gfx::DrawTarget* GetBufferTarget() const override { return nullptr; }
440
441
private:
442
  RefPtr<gfx::SourceSurface> mSource;
443
  RefPtr<gfx::SourceSurface> mSourceOnWhite;
444
  RefPtr<gfx::SourceSurface> mSourceDual;
445
};
446
447
} // namespace layers
448
} // namespace mozilla
449
450
#endif /* ROTATEDBUFFER_H_ */