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