Source code

Revision control

Other Tools

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