Bug 792663: Don't SyncFrontBufferToBackBuffer() while a buffer tracker isn't around...
[gecko.git] / gfx / layers / ThebesLayerBuffer.h
blob243b66f752a05b82c739c281788b0dd2b35dc537
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 THEBESLAYERBUFFER_H_
7 #define THEBESLAYERBUFFER_H_
9 #include "gfxContext.h"
10 #include "gfxASurface.h"
11 #include "nsRegion.h"
13 namespace mozilla {
14 namespace layers {
16 class AutoOpenSurface;
17 class ThebesLayer;
19 /**
20 * This class encapsulates the buffer used to retain ThebesLayer contents,
21 * i.e., the contents of the layer's GetVisibleRegion().
23 * This is a cairo/Thebes surface, but with a literal twist. Scrolling
24 * causes the layer's visible region to move. We want to keep
25 * reusing the same surface if the region size hasn't changed, but we don't
26 * want to keep moving the contents of the surface around in memory. So
27 * we use a trick.
28 * Consider just the vertical case, and suppose the buffer is H pixels
29 * high and we're scrolling down by N pixels. Instead of copying the
30 * buffer contents up by N pixels, we leave the buffer contents in place,
31 * and paint content rows H to H+N-1 into rows 0 to N-1 of the buffer.
32 * Then we can refresh the screen by painting rows N to H-1 of the buffer
33 * at row 0 on the screen, and then painting rows 0 to N-1 of the buffer
34 * at row H-N on the screen.
35 * mBufferRotation.y would be N in this example.
37 class ThebesLayerBuffer {
38 public:
39 typedef gfxASurface::gfxContentType ContentType;
41 /**
42 * Controls the size of the backing buffer of this.
43 * - SizedToVisibleBounds: the backing buffer is exactly the same
44 * size as the bounds of ThebesLayer's visible region
45 * - ContainsVisibleBounds: the backing buffer is large enough to
46 * fit visible bounds. May be larger.
48 enum BufferSizePolicy {
49 SizedToVisibleBounds,
50 ContainsVisibleBounds
53 ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy)
54 : mBufferProvider(nullptr)
55 , mBufferRotation(0,0)
56 , mBufferSizePolicy(aBufferSizePolicy)
58 MOZ_COUNT_CTOR(ThebesLayerBuffer);
60 virtual ~ThebesLayerBuffer()
62 MOZ_COUNT_DTOR(ThebesLayerBuffer);
65 /**
66 * Wipe out all retained contents. Call this when the entire
67 * buffer becomes invalid.
69 void Clear()
71 mBuffer = nullptr;
72 mBufferProvider = nullptr;
73 mBufferRect.SetEmpty();
76 /**
77 * This is returned by BeginPaint. The caller should draw into mContext.
78 * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
79 * by ThebesLayerBuffer and must be redrawn on the screen.
80 * mRegionToInvalidate is set when the buffer has changed from
81 * opaque to transparent or vice versa, since the details of rendering can
82 * depend on the buffer type. mDidSelfCopy is true if we kept our buffer
83 * but used MovePixels() to shift its content.
85 struct PaintState {
86 PaintState()
87 : mDidSelfCopy(false)
90 nsRefPtr<gfxContext> mContext;
91 nsIntRegion mRegionToDraw;
92 nsIntRegion mRegionToInvalidate;
93 bool mDidSelfCopy;
96 enum {
97 PAINT_WILL_RESAMPLE = 0x01,
98 PAINT_NO_ROTATION = 0x02
101 * Start a drawing operation. This returns a PaintState describing what
102 * needs to be drawn to bring the buffer up to date in the visible region.
103 * This queries aLayer to get the currently valid and visible regions.
104 * The returned mContext may be null if mRegionToDraw is empty.
105 * Otherwise it must not be null.
106 * mRegionToInvalidate will contain mRegionToDraw.
107 * @param aFlags when PAINT_WILL_RESAMPLE is passed, this indicates that
108 * buffer will be resampled when rendering (i.e the effective transform
109 * combined with the scale for the resolution is not just an integer
110 * translation). This will disable buffer rotation (since we don't want
111 * to resample across the rotation boundary) and will ensure that we
112 * make the entire buffer contents valid (since we don't want to sample
113 * invalid pixels outside the visible region, if the visible region doesn't
114 * fill the buffer bounds).
116 PaintState BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
117 uint32_t aFlags);
119 enum {
120 ALLOW_REPEAT = 0x01
123 * Return a new surface of |aSize| and |aType|.
124 * @param aFlags if ALLOW_REPEAT is set, then the buffer should be configured
125 * to allow repeat-mode, otherwise it should be in pad (clamp) mode
127 virtual already_AddRefed<gfxASurface>
128 CreateBuffer(ContentType aType, const nsIntSize& aSize, uint32_t aFlags) = 0;
131 * Get the underlying buffer, if any. This is useful because we can pass
132 * in the buffer as the default "reference surface" if there is one.
133 * Don't use it for anything else!
135 gfxASurface* GetBuffer() { return mBuffer; }
137 protected:
138 enum XSide {
139 LEFT, RIGHT
141 enum YSide {
142 TOP, BOTTOM
144 nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide);
146 * If aMask is non-null, then it is used as an alpha mask for rendering this
147 * buffer. aMaskTransform must be non-null if aMask is non-null, and is used
148 * to adjust the coordinate space of the mask.
150 void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide,
151 float aOpacity,
152 gfxASurface* aMask,
153 const gfxMatrix* aMaskTransform);
154 void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
155 gfxASurface* aMask = nullptr,
156 const gfxMatrix* aMaskTransform = nullptr);
159 * |BufferRect()| is the rect of device pixels that this
160 * ThebesLayerBuffer covers. That is what DrawBufferWithRotation()
161 * will paint when it's called.
163 const nsIntRect& BufferRect() const { return mBufferRect; }
164 const nsIntPoint& BufferRotation() const { return mBufferRotation; }
166 already_AddRefed<gfxASurface>
167 SetBuffer(gfxASurface* aBuffer,
168 const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation)
170 nsRefPtr<gfxASurface> tmp = mBuffer.forget();
171 mBuffer = aBuffer;
172 mBufferRect = aBufferRect;
173 mBufferRotation = aBufferRotation;
174 return tmp.forget();
178 * Set the buffer provider only. This is used with surfaces that
179 * require explicit map/unmap, which |aProvider| is used to do on
180 * demand in this code.
182 * It's the caller's responsibility to ensure |aProvider| is valid
183 * for the duration of operations it requests of this
184 * ThebesLayerBuffer. It's also the caller's responsibility to
185 * unset the provider when inactive, by calling
186 * SetBufferProvider(nullptr).
188 void SetBufferProvider(AutoOpenSurface* aProvider)
190 mBufferProvider = aProvider;
191 if (!mBufferProvider) {
192 mBuffer = nullptr;
193 } else {
194 // Only this buffer provider can give us a buffer. If we
195 // already have one, something has gone wrong.
196 MOZ_ASSERT(!mBuffer);
201 * Get a context at the specified resolution for updating |aBounds|,
202 * which must be contained within a single quadrant.
204 already_AddRefed<gfxContext>
205 GetContextForQuadrantUpdate(const nsIntRect& aBounds);
207 private:
208 // Buffer helpers. Don't use mBuffer directly; instead use one of
209 // these helpers.
212 * Return the buffer's content type. Requires a valid buffer or
213 * buffer provider.
215 gfxASurface::gfxContentType BufferContentType();
216 bool BufferSizeOkFor(const nsIntSize& aSize);
218 * If the buffer hasn't been mapped, map it and return it.
220 gfxASurface* EnsureBuffer();
222 * True if we have a buffer where we can get it (but not necessarily
223 * mapped currently).
225 bool HaveBuffer();
227 nsRefPtr<gfxASurface> mBuffer;
229 * This member is only set transiently. It's used to map mBuffer
230 * when we're using surfaces that require explicit map/unmap.
232 AutoOpenSurface* mBufferProvider;
233 /** The area of the ThebesLayer that is covered by the buffer as a whole */
234 nsIntRect mBufferRect;
236 * The x and y rotation of the buffer. Conceptually the buffer
237 * has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
238 * is tiled to fill the plane, and the result is clipped to mBufferRect.
239 * So the pixel at mBufferRotation within the buffer is what gets painted at
240 * mBufferRect.TopLeft().
241 * This is "rotation" in the sense of rotating items in a linear buffer,
242 * where items falling off the end of the buffer are returned to the
243 * buffer at the other end, not 2D rotation!
245 nsIntPoint mBufferRotation;
246 BufferSizePolicy mBufferSizePolicy;
252 #endif /* THEBESLAYERBUFFER_H_ */