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 : #ifndef ROTATEDBUFFER_H_
7 : #define ROTATEDBUFFER_H_
8 :
9 : #include "gfxTypes.h"
10 : #include <stdint.h> // for uint32_t
11 : #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
12 : #include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
13 : #include "mozilla/gfx/2D.h" // for DrawTarget, etc
14 : #include "mozilla/gfx/MatrixFwd.h" // for Matrix
15 : #include "mozilla/mozalloc.h" // for operator delete
16 : #include "nsCOMPtr.h" // for already_AddRefed
17 : #include "nsDebug.h" // for NS_RUNTIMEABORT
18 : #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
19 : #include "nsRegion.h" // for nsIntRegion
20 : #include "LayersTypes.h"
21 :
22 : namespace mozilla {
23 : namespace layers {
24 :
25 : class TextureClient;
26 : class PaintedLayer;
27 :
28 : /**
29 : * This is a cairo/Thebes surface, but with a literal twist. Scrolling
30 : * causes the layer's visible region to move. We want to keep
31 : * reusing the same surface if the region size hasn't changed, but we don't
32 : * want to keep moving the contents of the surface around in memory. So
33 : * we use a trick.
34 : * Consider just the vertical case, and suppose the buffer is H pixels
35 : * high and we're scrolling down by N pixels. Instead of copying the
36 : * buffer contents up by N pixels, we leave the buffer contents in place,
37 : * and paint content rows H to H+N-1 into rows 0 to N-1 of the buffer.
38 : * Then we can refresh the screen by painting rows N to H-1 of the buffer
39 : * at row 0 on the screen, and then painting rows 0 to N-1 of the buffer
40 : * at row H-N on the screen.
41 : * mBufferRotation.y would be N in this example.
42 : */
43 : class RotatedBuffer {
44 : public:
45 : typedef gfxContentType ContentType;
46 :
47 13 : RotatedBuffer(const gfx::IntRect& aBufferRect,
48 : const gfx::IntPoint& aBufferRotation)
49 13 : : mBufferRect(aBufferRect)
50 : , mBufferRotation(aBufferRotation)
51 13 : , mDidSelfCopy(false)
52 13 : { }
53 79 : RotatedBuffer()
54 79 : : mDidSelfCopy(false)
55 79 : { }
56 :
57 : /*
58 : * Which buffer should be drawn to/read from.
59 : */
60 : enum ContextSource {
61 : BUFFER_BLACK, // The normal buffer, or buffer with black background when using component alpha.
62 : BUFFER_WHITE, // The buffer with white background, only valid with component alpha.
63 : BUFFER_BOTH // The combined black/white buffers, only valid for writing operations, not reading.
64 : };
65 : // It is the callers repsonsibility to ensure aTarget is flushed after calling
66 : // this method.
67 : void DrawBufferWithRotation(gfx::DrawTarget* aTarget, ContextSource aSource,
68 : float aOpacity = 1.0,
69 : gfx::CompositionOp aOperator = gfx::CompositionOp::OP_OVER,
70 : gfx::SourceSurface* aMask = nullptr,
71 : const gfx::Matrix* aMaskTransform = nullptr) const;
72 :
73 : /**
74 : * |BufferRect()| is the rect of device pixels that this
75 : * RotatedBuffer covers. That is what DrawBufferWithRotation()
76 : * will paint when it's called.
77 : */
78 66 : const gfx::IntRect& BufferRect() const { return mBufferRect; }
79 33 : const gfx::IntPoint& BufferRotation() const { return mBufferRotation; }
80 :
81 : virtual bool HaveBuffer() const = 0;
82 : virtual bool HaveBufferOnWhite() const = 0;
83 :
84 : virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const = 0;
85 :
86 : protected:
87 :
88 : enum XSide {
89 : LEFT, RIGHT
90 : };
91 : enum YSide {
92 : TOP, BOTTOM
93 : };
94 : gfx::IntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
95 :
96 : gfx::Rect GetSourceRectangle(XSide aXSide, YSide aYSide) const;
97 :
98 : /*
99 : * If aMask is non-null, then it is used as an alpha mask for rendering this
100 : * buffer. aMaskTransform must be non-null if aMask is non-null, and is used
101 : * to adjust the coordinate space of the mask.
102 : */
103 : void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
104 : ContextSource aSource,
105 : float aOpacity,
106 : gfx::CompositionOp aOperator,
107 : gfx::SourceSurface* aMask,
108 : const gfx::Matrix* aMaskTransform) const;
109 :
110 : /** The area of the PaintedLayer that is covered by the buffer as a whole */
111 : gfx::IntRect mBufferRect;
112 : /**
113 : * The x and y rotation of the buffer. Conceptually the buffer
114 : * has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
115 : * is tiled to fill the plane, and the result is clipped to mBufferRect.
116 : * So the pixel at mBufferRotation within the buffer is what gets painted at
117 : * mBufferRect.TopLeft().
118 : * This is "rotation" in the sense of rotating items in a linear buffer,
119 : * where items falling off the end of the buffer are returned to the
120 : * buffer at the other end, not 2D rotation!
121 : */
122 : gfx::IntPoint mBufferRotation;
123 : // When this is true it means that all pixels have moved inside the buffer.
124 : // It's not possible to sync with another buffer without a full copy.
125 : bool mDidSelfCopy;
126 : };
127 :
128 13 : class SourceRotatedBuffer : public RotatedBuffer
129 : {
130 : public:
131 13 : SourceRotatedBuffer(gfx::SourceSurface* aSource, gfx::SourceSurface* aSourceOnWhite,
132 : const gfx::IntRect& aBufferRect,
133 : const gfx::IntPoint& aBufferRotation)
134 13 : : RotatedBuffer(aBufferRect, aBufferRotation)
135 : , mSource(aSource)
136 13 : , mSourceOnWhite(aSourceOnWhite)
137 13 : { }
138 :
139 : virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
140 :
141 0 : virtual bool HaveBuffer() const { return !!mSource; }
142 13 : virtual bool HaveBufferOnWhite() const { return !!mSourceOnWhite; }
143 :
144 : private:
145 : RefPtr<gfx::SourceSurface> mSource;
146 : RefPtr<gfx::SourceSurface> mSourceOnWhite;
147 : };
148 :
149 : // Mixin class for classes which need logic for loaning out a draw target.
150 : // See comments on BorrowDrawTargetForQuadrantUpdate.
151 152 : class BorrowDrawTarget
152 : {
153 : protected:
154 : void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
155 :
156 : // The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
157 : // be used, we just keep a reference to ensure it is kept alive and so we can
158 : // correctly restore state when it is returned.
159 : RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
160 : gfx::Matrix mLoanedTransform;
161 : };
162 :
163 : /**
164 : * This class encapsulates the buffer used to retain PaintedLayer contents,
165 : * i.e., the contents of the layer's GetVisibleRegion().
166 : */
167 : class RotatedContentBuffer : public RotatedBuffer
168 : , public BorrowDrawTarget
169 : {
170 : public:
171 : typedef gfxContentType ContentType;
172 :
173 : /**
174 : * Controls the size of the backing buffer of this.
175 : * - SizedToVisibleBounds: the backing buffer is exactly the same
176 : * size as the bounds of PaintedLayer's visible region
177 : * - ContainsVisibleBounds: the backing buffer is large enough to
178 : * fit visible bounds. May be larger.
179 : */
180 : enum BufferSizePolicy {
181 : SizedToVisibleBounds,
182 : ContainsVisibleBounds
183 : };
184 :
185 79 : explicit RotatedContentBuffer(BufferSizePolicy aBufferSizePolicy)
186 79 : : mBufferProvider(nullptr)
187 : , mBufferProviderOnWhite(nullptr)
188 79 : , mBufferSizePolicy(aBufferSizePolicy)
189 : {
190 79 : MOZ_COUNT_CTOR(RotatedContentBuffer);
191 79 : }
192 73 : virtual ~RotatedContentBuffer()
193 146 : {
194 73 : MOZ_COUNT_DTOR(RotatedContentBuffer);
195 73 : }
196 :
197 : /**
198 : * Wipe out all retained contents. Call this when the entire
199 : * buffer becomes invalid.
200 : */
201 99 : void Clear()
202 : {
203 99 : UnlockBuffers();
204 99 : mDTBuffer = nullptr;
205 99 : mDTBufferOnWhite = nullptr;
206 99 : mBufferProvider = nullptr;
207 99 : mBufferProviderOnWhite = nullptr;
208 99 : mBufferRect.SetEmpty();
209 99 : }
210 :
211 : /**
212 : * This is returned by BeginPaint. The caller should draw into mTarget.
213 : * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
214 : * by RotatedContentBuffer and must be redrawn on the screen.
215 : * mRegionToInvalidate is set when the buffer has changed from
216 : * opaque to transparent or vice versa, since the details of rendering can
217 : * depend on the buffer type. mDidSelfCopy is true if we kept our buffer
218 : * but used MovePixels() to shift its content.
219 : */
220 77 : struct PaintState {
221 77 : PaintState()
222 77 : : mRegionToDraw()
223 : , mRegionToInvalidate()
224 : , mMode(SurfaceMode::SURFACE_NONE)
225 : , mClip(DrawRegionClip::NONE)
226 : , mContentType(gfxContentType::SENTINEL)
227 77 : , mDidSelfCopy(false)
228 77 : {}
229 :
230 : nsIntRegion mRegionToDraw;
231 : nsIntRegion mRegionToInvalidate;
232 : SurfaceMode mMode;
233 : DrawRegionClip mClip;
234 : ContentType mContentType;
235 : bool mDidSelfCopy;
236 : };
237 :
238 : enum {
239 : PAINT_WILL_RESAMPLE = 0x01,
240 : PAINT_NO_ROTATION = 0x02,
241 : PAINT_CAN_DRAW_ROTATED = 0x04
242 : };
243 : /**
244 : * Start a drawing operation. This returns a PaintState describing what
245 : * needs to be drawn to bring the buffer up to date in the visible region.
246 : * This queries aLayer to get the currently valid and visible regions.
247 : * The returned mTarget may be null if mRegionToDraw is empty.
248 : * Otherwise it must not be null.
249 : * mRegionToInvalidate will contain mRegionToDraw.
250 : * @param aFlags when PAINT_WILL_RESAMPLE is passed, this indicates that
251 : * buffer will be resampled when rendering (i.e the effective transform
252 : * combined with the scale for the resolution is not just an integer
253 : * translation). This will disable buffer rotation (since we don't want
254 : * to resample across the rotation boundary) and will ensure that we
255 : * make the entire buffer contents valid (since we don't want to sample
256 : * invalid pixels outside the visible region, if the visible region doesn't
257 : * fill the buffer bounds).
258 : * PAINT_CAN_DRAW_ROTATED can be passed if the caller supports drawing
259 : * rotated content that crosses the physical buffer boundary. The caller
260 : * will need to call BorrowDrawTargetForPainting multiple times to achieve
261 : * this.
262 : */
263 : PaintState BeginPaint(PaintedLayer* aLayer,
264 : uint32_t aFlags);
265 :
266 90 : struct DrawIterator {
267 : friend class RotatedContentBuffer;
268 90 : DrawIterator()
269 90 : : mCount(0)
270 90 : {}
271 :
272 : nsIntRegion mDrawRegion;
273 :
274 : private:
275 : uint32_t mCount;
276 : };
277 :
278 : /**
279 : * Fetch a DrawTarget for rendering. The DrawTarget remains owned by
280 : * this. See notes on BorrowDrawTargetForQuadrantUpdate.
281 : * May return null. If the return value is non-null, it must be
282 : * 'un-borrowed' using ReturnDrawTarget.
283 : *
284 : * If PAINT_CAN_DRAW_ROTATED was specified for BeginPaint, then the caller
285 : * must call this function repeatedly (with an iterator) until it returns
286 : * nullptr. The caller should draw the mDrawRegion of the iterator instead
287 : * of mRegionToDraw in the PaintState.
288 : *
289 : * @param aPaintState Paint state data returned by a call to BeginPaint
290 : * @param aIter Paint state iterator. Only required if PAINT_CAN_DRAW_ROTATED
291 : * was specified to BeginPaint.
292 : */
293 : gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
294 : DrawIterator* aIter = nullptr);
295 :
296 : enum {
297 : BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
298 : // component alpha.
299 : };
300 : /**
301 : * Return a new surface of |aSize| and |aType|.
302 : *
303 : * If the created buffer supports azure content, then the result(s) will
304 : * be returned in aBlackDT/aWhiteDT, otherwise aBlackSurface/aWhiteSurface
305 : * will be used.
306 : */
307 : virtual void
308 : CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
309 : RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) = 0;
310 :
311 : /**
312 : * Get the underlying buffer, if any. This is useful because we can pass
313 : * in the buffer as the default "reference surface" if there is one.
314 : * Don't use it for anything else!
315 : */
316 : gfx::DrawTarget* GetDTBuffer() { return mDTBuffer; }
317 : gfx::DrawTarget* GetDTBufferOnWhite() { return mDTBufferOnWhite; }
318 :
319 : virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
320 :
321 : /**
322 : * Complete the drawing operation. The region to draw must have been
323 : * drawn before this is called. The contents of the buffer are drawn
324 : * to aTarget.
325 : */
326 : void DrawTo(PaintedLayer* aLayer,
327 : gfx::DrawTarget* aTarget,
328 : float aOpacity,
329 : gfx::CompositionOp aOp,
330 : gfx::SourceSurface* aMask,
331 : const gfx::Matrix* aMaskTransform);
332 :
333 : protected:
334 : // new texture client versions
335 129 : void SetBufferProvider(TextureClient* aClient)
336 : {
337 : // Only this buffer provider can give us a buffer. If we
338 : // already have one, something has gone wrong.
339 129 : MOZ_ASSERT(!aClient || !mDTBuffer || !mDTBuffer->IsValid());
340 :
341 129 : mBufferProvider = aClient;
342 129 : if (!mBufferProvider) {
343 77 : mDTBuffer = nullptr;
344 : }
345 129 : }
346 :
347 77 : void SetBufferProviderOnWhite(TextureClient* aClient)
348 : {
349 : // Only this buffer provider can give us a buffer. If we
350 : // already have one, something has gone wrong.
351 77 : MOZ_ASSERT(!aClient || !mDTBufferOnWhite || !mDTBufferOnWhite->IsValid());
352 :
353 77 : mBufferProviderOnWhite = aClient;
354 77 : if (!mBufferProviderOnWhite) {
355 77 : mDTBufferOnWhite = nullptr;
356 : }
357 77 : }
358 :
359 : /**
360 : * Get a draw target at the specified resolution for updating |aBounds|,
361 : * which must be contained within a single quadrant.
362 : *
363 : * The result should only be held temporarily by the caller (it will be kept
364 : * alive by this). Once used it should be returned using ReturnDrawTarget.
365 : * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
366 : * first calling ReturnDrawTarget.
367 : *
368 : * ReturnDrawTarget will restore the transform on the draw target. But it is
369 : * the callers responsibility to restore the clip. The caller should flush the
370 : * draw target, if necessary.
371 : */
372 : gfx::DrawTarget*
373 : BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
374 : ContextSource aSource,
375 : DrawIterator* aIter);
376 :
377 : static bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
378 :
379 : protected:
380 : /**
381 : * Return the buffer's content type. Requires a valid buffer or
382 : * buffer provider.
383 : */
384 : gfxContentType BufferContentType();
385 : bool BufferSizeOkFor(const gfx::IntSize& aSize);
386 : /**
387 : * If the buffer hasn't been mapped, map it.
388 : */
389 : bool EnsureBuffer();
390 : bool EnsureBufferOnWhite();
391 :
392 : // Flush our buffers if they are mapped.
393 : void FlushBuffers();
394 :
395 : /**
396 : * True if we have a buffer where we can get it (but not necessarily
397 : * mapped currently).
398 : */
399 : virtual bool HaveBuffer() const;
400 : virtual bool HaveBufferOnWhite() const;
401 :
402 : /**
403 : * Any actions that should be performed at the last moment before we begin
404 : * rendering the next frame. I.e., after we calculate what we will draw,
405 : * but before we rotate the buffer and possibly create new buffers.
406 : * aRegionToDraw is the region which is guaranteed to be overwritten when
407 : * drawing the next frame.
408 : */
409 0 : virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) {}
410 :
411 0 : virtual bool LockBuffers() { return true; }
412 99 : virtual void UnlockBuffers() {}
413 :
414 : RefPtr<gfx::DrawTarget> mDTBuffer;
415 : RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
416 :
417 : /**
418 : * These members are only set transiently. They're used to map mDTBuffer
419 : * when we're using surfaces that require explicit map/unmap. Only one
420 : * may be used at a time.
421 : */
422 : TextureClient* mBufferProvider;
423 : TextureClient* mBufferProviderOnWhite;
424 :
425 : BufferSizePolicy mBufferSizePolicy;
426 : };
427 :
428 : } // namespace layers
429 : } // namespace mozilla
430 :
431 : #endif /* ROTATEDBUFFER_H_ */
|