/work/obj-fuzz/dist/include/mozilla/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 | | { } |
73 | | RotatedBuffer() |
74 | | : mCapture(nullptr) |
75 | | , mDidSelfCopy(false) |
76 | 0 | { } |
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 | 0 | { |
97 | 0 | return !!mCapture; |
98 | 0 | } |
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 | | {} |
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 | | { |
171 | | } |
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 | | const gfx::IntRect& BufferRect() const { return mBufferRect; } |
203 | | 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 | | void SetBufferRect(const gfx::IntRect& aBufferRect) { |
210 | | mBufferRect = aBufferRect; |
211 | | } |
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 | | void SetBufferRotation(const gfx::IntPoint& aBufferRotation) { |
218 | | mBufferRotation = aBufferRotation; |
219 | | } |
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 | | bool DidSelfCopy() const { return mDidSelfCopy; } |
227 | | |
228 | | /** |
229 | | * Clears the self copy flag. |
230 | | */ |
231 | | 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 | | { |
249 | | return GetBufferTarget()->Snapshot(); |
250 | | } |
251 | | virtual gfx::DrawTarget* GetBufferTarget() const = 0; |
252 | | |
253 | | virtual TextureClient* GetClient() const { |
254 | | return nullptr; |
255 | | } |
256 | | virtual TextureClient* GetClientOnWhite() const { |
257 | | return nullptr; |
258 | | } |
259 | | |
260 | | protected: |
261 | | virtual ~RotatedBuffer() |
262 | | { |
263 | | MOZ_ASSERT(!mCapture); |
264 | | } |
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 | | { |
278 | | if (mCapture) { |
279 | | return mCapture; |
280 | | } |
281 | | return GetBufferTarget(); |
282 | | } |
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 | | { } |
334 | | |
335 | | virtual bool IsLocked() override; |
336 | | virtual bool Lock(OpenMode aMode) override; |
337 | | virtual void Unlock() override; |
338 | | |
339 | | virtual bool HaveBuffer() const override { return !!mClient; } |
340 | | 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 | | virtual TextureClient* GetClient() const override { return mClient; } |
347 | | 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 | 0 | { } |
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 | | { |
387 | | if (mTargetOnWhite) { |
388 | | mTargetDual = gfx::Factory::CreateDualDrawTarget(mTarget, mTargetOnWhite); |
389 | | } else { |
390 | | mTargetDual = mTarget; |
391 | | } |
392 | | } |
393 | | |
394 | | virtual bool IsLocked() override { return false; } |
395 | | virtual bool Lock(OpenMode aMode) override { return true; } |
396 | | virtual void Unlock() override {} |
397 | | |
398 | | virtual bool HaveBuffer() const override { return !!mTargetDual; } |
399 | | 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 | | { |
425 | | mSourceDual = gfx::Factory::CreateDualSourceSurface(mSource, mSourceOnWhite); |
426 | | } |
427 | | |
428 | | virtual bool IsLocked() override { return false; } |
429 | | virtual bool Lock(OpenMode aMode) override { return false; } |
430 | | virtual void Unlock() override {} |
431 | | |
432 | | virtual already_AddRefed<gfx::SourceSurface> GetBufferSource() const override; |
433 | | |
434 | | virtual gfx::SurfaceFormat GetFormat() const override; |
435 | | |
436 | | virtual bool HaveBuffer() const override { return !!mSourceDual; } |
437 | | virtual bool HaveBufferOnWhite() const override { return !!mSourceOnWhite; } |
438 | | |
439 | | 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_ */ |