Line data Source code
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 : /**
8 : * A SurfacePipe is a pipeline that consists of a series of SurfaceFilters
9 : * terminating in a SurfaceSink. Each SurfaceFilter transforms the image data in
10 : * some way before the SurfaceSink ultimately writes it to the surface. This
11 : * design allows for each transformation to be tested independently, for the
12 : * transformations to be combined as needed to meet the needs of different
13 : * situations, and for all image decoders to share the same code for these
14 : * transformations.
15 : *
16 : * Writing to the SurfacePipe is done using lambdas that act as generator
17 : * functions. Because the SurfacePipe machinery controls where the writes take
18 : * place, a bug in an image decoder cannot cause a buffer overflow of the
19 : * underlying surface.
20 : */
21 :
22 : #ifndef mozilla_image_SurfacePipe_h
23 : #define mozilla_image_SurfacePipe_h
24 :
25 : #include <stdint.h>
26 :
27 : #include "nsDebug.h"
28 :
29 : #include "mozilla/Likely.h"
30 : #include "mozilla/Maybe.h"
31 : #include "mozilla/Move.h"
32 : #include "mozilla/UniquePtr.h"
33 : #include "mozilla/Unused.h"
34 : #include "mozilla/Variant.h"
35 : #include "mozilla/gfx/2D.h"
36 :
37 : namespace mozilla {
38 : namespace image {
39 :
40 : class Decoder;
41 :
42 : /**
43 : * An invalid rect for a surface. Results are given both in the space of the
44 : * input image (i.e., before any SurfaceFilters are applied) and in the space
45 : * of the output surface (after all SurfaceFilters).
46 : */
47 1538 : struct SurfaceInvalidRect
48 : {
49 : gfx::IntRect mInputSpaceRect; /// The invalid rect in pre-SurfacePipe space.
50 : gfx::IntRect mOutputSpaceRect; /// The invalid rect in post-SurfacePipe space.
51 : };
52 :
53 : /**
54 : * An enum used to allow the lambdas passed to WritePixels() to communicate
55 : * their state to the caller.
56 : */
57 : enum class WriteState : uint8_t
58 : {
59 : NEED_MORE_DATA, /// The lambda ran out of data.
60 :
61 : FINISHED, /// The lambda is done writing to the surface; future writes
62 : /// will fail.
63 :
64 : FAILURE /// The lambda encountered an error. The caller may recover
65 : /// if possible and continue to write. (This never indicates
66 : /// an error in the SurfacePipe machinery itself; it's only
67 : /// generated by the lambdas.)
68 : };
69 :
70 : /**
71 : * A template alias used to make the return value of WritePixels() lambdas
72 : * (which may return either a pixel value or a WriteState) easier to specify.
73 : */
74 : template <typename PixelType>
75 : using NextPixel = Variant<PixelType, WriteState>;
76 :
77 : /**
78 : * SurfaceFilter is the abstract superclass of SurfacePipe pipeline stages. It
79 : * implements the the code that actually writes to the surface - WritePixels()
80 : * and the other Write*() methods - which are non-virtual for efficiency.
81 : *
82 : * SurfaceFilter's API is nonpublic; only SurfacePipe and other SurfaceFilters
83 : * should use it. Non-SurfacePipe code should use the methods on SurfacePipe.
84 : *
85 : * To implement a SurfaceFilter, it's necessary to subclass SurfaceFilter and
86 : * implement, at a minimum, the pure virtual methods. It's also necessary to
87 : * define a Config struct with a Filter typedef member that identifies the
88 : * matching SurfaceFilter class, and a Configure() template method. See an
89 : * existing SurfaceFilter subclass, such as RemoveFrameRectFilter, for an
90 : * example of how the Configure() method must be implemented. It takes a list of
91 : * Config structs, passes the tail of the list to the next filter in the chain's
92 : * Configure() method, and then uses the head of the list to configure itself. A
93 : * SurfaceFilter's Configure() method must also call
94 : * SurfaceFilter::ConfigureFilter() to provide the Write*() methods with the
95 : * information they need to do their jobs.
96 : */
97 : class SurfaceFilter
98 : {
99 : public:
100 51 : SurfaceFilter()
101 51 : : mRowPointer(nullptr)
102 : , mCol(0)
103 51 : , mPixelSize(0)
104 51 : { }
105 :
106 48 : virtual ~SurfaceFilter() { }
107 :
108 : /**
109 : * Reset this surface to the first row. It's legal for this filter to throw
110 : * away any previously written data at this point, as all rows must be written
111 : * to on every pass.
112 : *
113 : * @return a pointer to the buffer for the first row.
114 : */
115 51 : uint8_t* ResetToFirstRow()
116 : {
117 51 : mCol = 0;
118 51 : mRowPointer = DoResetToFirstRow();
119 51 : return mRowPointer;
120 : }
121 :
122 : /**
123 : * Called by WritePixels() to advance this filter to the next row.
124 : *
125 : * @return a pointer to the buffer for the next row, or nullptr to indicate
126 : * that we've finished the entire surface.
127 : */
128 1543 : uint8_t* AdvanceRow()
129 : {
130 1543 : mCol = 0;
131 1543 : mRowPointer = DoAdvanceRow();
132 1542 : return mRowPointer;
133 : }
134 :
135 : /// @return a pointer to the buffer for the current row.
136 0 : uint8_t* CurrentRowPointer() const { return mRowPointer; }
137 :
138 : /// @return true if we've finished writing to the surface.
139 3084 : bool IsSurfaceFinished() const { return mRowPointer == nullptr; }
140 :
141 : /// @return the input size this filter expects.
142 9253 : gfx::IntSize InputSize() const { return mInputSize; }
143 :
144 : /**
145 : * Write pixels to the surface one at a time by repeatedly calling a lambda
146 : * that yields pixels. WritePixels() is completely memory safe.
147 : *
148 : * Writing continues until every pixel in the surface has been written to
149 : * (i.e., IsSurfaceFinished() returns true) or the lambda returns a WriteState
150 : * which WritePixels() will return to the caller.
151 : *
152 : * The template parameter PixelType must be uint8_t (for paletted surfaces) or
153 : * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
154 : * size passed to ConfigureFilter().
155 : *
156 : * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
157 : * which means we can remove the PixelType template parameter from this
158 : * method.
159 : *
160 : * @param aFunc A lambda that functions as a generator, yielding the next
161 : * pixel in the surface each time it's called. The lambda must
162 : * return a NextPixel<PixelType> value.
163 : *
164 : * @return A WriteState value indicating the lambda generator's state.
165 : * WritePixels() itself will return WriteState::FINISHED if writing
166 : * has finished, regardless of the lambda's internal state.
167 : */
168 : template <typename PixelType, typename Func>
169 2 : WriteState WritePixels(Func aFunc)
170 : {
171 4 : Maybe<WriteState> result;
172 6 : while (!(result = DoWritePixelsToRow<PixelType>(Forward<Func>(aFunc)))) { }
173 :
174 4 : return *result;
175 : }
176 :
177 : /**
178 : * A variant of WritePixels() that writes a single row of pixels to the
179 : * surface one at a time by repeatedly calling a lambda that yields pixels.
180 : * WritePixelsToRow() is completely memory safe.
181 : *
182 : * Writing continues until every pixel in the row has been written to. If the
183 : * surface is complete at that pointer, WriteState::FINISHED is returned;
184 : * otherwise, WritePixelsToRow() returns WriteState::NEED_MORE_DATA. The
185 : * lambda can terminate writing early by returning a WriteState itself, which
186 : * WritePixelsToRow() will return to the caller.
187 : *
188 : * The template parameter PixelType must be uint8_t (for paletted surfaces) or
189 : * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
190 : * size passed to ConfigureFilter().
191 : *
192 : * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
193 : * which means we can remove the PixelType template parameter from this
194 : * method.
195 : *
196 : * @param aFunc A lambda that functions as a generator, yielding the next
197 : * pixel in the surface each time it's called. The lambda must
198 : * return a NextPixel<PixelType> value.
199 : *
200 : * @return A WriteState value indicating the lambda generator's state.
201 : * WritePixels() itself will return WriteState::FINISHED if writing
202 : * the entire surface has finished, or WriteState::NEED_MORE_DATA if
203 : * writing the row has finished, regardless of the lambda's internal
204 : * state.
205 : */
206 : template <typename PixelType, typename Func>
207 1538 : WriteState WritePixelsToRow(Func aFunc)
208 : {
209 1538 : return DoWritePixelsToRow<PixelType>(Forward<Func>(aFunc))
210 3076 : .valueOr(WriteState::NEED_MORE_DATA);
211 : }
212 :
213 : /**
214 : * Write a row to the surface by copying from a buffer. This is bounds checked
215 : * and memory safe with respect to the surface, but care must still be taken
216 : * by the caller not to overread the source buffer. This variant of
217 : * WriteBuffer() requires a source buffer which contains |mInputSize.width|
218 : * pixels.
219 : *
220 : * The template parameter PixelType must be uint8_t (for paletted surfaces) or
221 : * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
222 : * size passed to ConfigureFilter().
223 : *
224 : * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
225 : * which means we can remove the PixelType template parameter from this
226 : * method.
227 : *
228 : * @param aSource A buffer to copy from. This buffer must be
229 : * |mInputSize.width| pixels wide, which means
230 : * |mInputSize.width * sizeof(PixelType)| bytes. May not be
231 : * null.
232 : *
233 : * @return WriteState::FINISHED if the entire surface has been written to.
234 : * Otherwise, returns WriteState::NEED_MORE_DATA. If a null |aSource|
235 : * value is passed, returns WriteState::FAILURE.
236 : */
237 : template <typename PixelType>
238 0 : WriteState WriteBuffer(const PixelType* aSource)
239 : {
240 0 : return WriteBuffer(aSource, 0, mInputSize.width);
241 : }
242 :
243 : /**
244 : * Write a row to the surface by copying from a buffer. This is bounds checked
245 : * and memory safe with respect to the surface, but care must still be taken
246 : * by the caller not to overread the source buffer. This variant of
247 : * WriteBuffer() reads at most @aLength pixels from the buffer and writes them
248 : * to the row starting at @aStartColumn. Any pixels in columns before
249 : * @aStartColumn or after the pixels copied from the buffer are cleared.
250 : *
251 : * Bounds checking failures produce warnings in debug builds because although
252 : * the bounds checking maintains safety, this kind of failure could indicate a
253 : * bug in the calling code.
254 : *
255 : * The template parameter PixelType must be uint8_t (for paletted surfaces) or
256 : * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
257 : * size passed to ConfigureFilter().
258 : *
259 : * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
260 : * which means we can remove the PixelType template parameter from this
261 : * method.
262 : *
263 : * @param aSource A buffer to copy from. This buffer must be @aLength pixels
264 : * wide, which means |aLength * sizeof(PixelType)| bytes. May
265 : * not be null.
266 : * @param aStartColumn The column to start writing to in the row. Columns
267 : * before this are cleared.
268 : * @param aLength The number of bytes, at most, which may be copied from
269 : * @aSource. Fewer bytes may be copied in practice due to
270 : * bounds checking.
271 : *
272 : * @return WriteState::FINISHED if the entire surface has been written to.
273 : * Otherwise, returns WriteState::NEED_MORE_DATA. If a null |aSource|
274 : * value is passed, returns WriteState::FAILURE.
275 : */
276 : template <typename PixelType>
277 0 : WriteState WriteBuffer(const PixelType* aSource,
278 : const size_t aStartColumn,
279 : const size_t aLength)
280 : {
281 0 : MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
282 0 : MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
283 0 : MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
284 :
285 0 : if (IsSurfaceFinished()) {
286 0 : return WriteState::FINISHED; // Already done.
287 : }
288 :
289 0 : if (MOZ_UNLIKELY(!aSource)) {
290 0 : NS_WARNING("Passed a null pointer to WriteBuffer");
291 0 : return WriteState::FAILURE;
292 : }
293 :
294 0 : PixelType* dest = reinterpret_cast<PixelType*>(mRowPointer);
295 :
296 : // Clear the area before |aStartColumn|.
297 0 : const size_t prefixLength = std::min<size_t>(mInputSize.width, aStartColumn);
298 0 : if (MOZ_UNLIKELY(prefixLength != aStartColumn)) {
299 0 : NS_WARNING("Provided starting column is out-of-bounds in WriteBuffer");
300 : }
301 :
302 0 : memset(dest, 0, mInputSize.width * sizeof(PixelType));
303 0 : dest += prefixLength;
304 :
305 : // Write |aLength| pixels from |aSource| into the row, with bounds checking.
306 : const size_t bufferLength =
307 0 : std::min<size_t>(mInputSize.width - prefixLength, aLength);
308 0 : if (MOZ_UNLIKELY(bufferLength != aLength)) {
309 0 : NS_WARNING("Provided buffer length is out-of-bounds in WriteBuffer");
310 : }
311 :
312 0 : memcpy(dest, aSource, bufferLength * sizeof(PixelType));
313 0 : dest += bufferLength;
314 :
315 : // Clear the rest of the row.
316 0 : const size_t suffixLength = mInputSize.width - (prefixLength + bufferLength);
317 0 : memset(dest, 0, suffixLength * sizeof(PixelType));
318 :
319 0 : AdvanceRow();
320 :
321 0 : return IsSurfaceFinished() ? WriteState::FINISHED
322 0 : : WriteState::NEED_MORE_DATA;
323 : }
324 :
325 : /**
326 : * Write an empty row to the surface. If some pixels have already been written
327 : * to this row, they'll be discarded.
328 : *
329 : * @return WriteState::FINISHED if the entire surface has been written to.
330 : * Otherwise, returns WriteState::NEED_MORE_DATA.
331 : */
332 0 : WriteState WriteEmptyRow()
333 : {
334 0 : if (IsSurfaceFinished()) {
335 0 : return WriteState::FINISHED; // Already done.
336 : }
337 :
338 0 : memset(mRowPointer, 0, mInputSize.width * mPixelSize);
339 0 : AdvanceRow();
340 :
341 0 : return IsSurfaceFinished() ? WriteState::FINISHED
342 0 : : WriteState::NEED_MORE_DATA;
343 : }
344 :
345 : /**
346 : * Write a row to the surface by calling a lambda that uses a pointer to
347 : * directly write to the row. This is unsafe because SurfaceFilter can't
348 : * provide any bounds checking; that's up to the lambda itself. For this
349 : * reason, the other Write*() methods should be preferred whenever it's
350 : * possible to use them; WriteUnsafeComputedRow() should be used only when
351 : * it's absolutely necessary to avoid extra copies or other performance
352 : * penalties.
353 : *
354 : * This method should never be exposed to SurfacePipe consumers; it's strictly
355 : * for use in SurfaceFilters. If external code needs this method, it should
356 : * probably be turned into a SurfaceFilter.
357 : *
358 : * The template parameter PixelType must be uint8_t (for paletted surfaces) or
359 : * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
360 : * size passed to ConfigureFilter().
361 : *
362 : * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
363 : * which means we can remove the PixelType template parameter from this
364 : * method.
365 : *
366 : * @param aFunc A lambda that writes directly to the row.
367 : *
368 : * @return WriteState::FINISHED if the entire surface has been written to.
369 : * Otherwise, returns WriteState::NEED_MORE_DATA.
370 : */
371 : template <typename PixelType, typename Func>
372 0 : WriteState WriteUnsafeComputedRow(Func aFunc)
373 : {
374 0 : MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
375 0 : MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
376 0 : MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
377 :
378 0 : if (IsSurfaceFinished()) {
379 0 : return WriteState::FINISHED; // Already done.
380 : }
381 :
382 : // Call the provided lambda with a pointer to the buffer for the current
383 : // row. This is unsafe because we can't do any bounds checking; the lambda
384 : // itself has to be responsible for that.
385 0 : PixelType* rowPtr = reinterpret_cast<PixelType*>(mRowPointer);
386 0 : aFunc(rowPtr, mInputSize.width);
387 0 : AdvanceRow();
388 :
389 0 : return IsSurfaceFinished() ? WriteState::FINISHED
390 0 : : WriteState::NEED_MORE_DATA;
391 : }
392 :
393 : //////////////////////////////////////////////////////////////////////////////
394 : // Methods Subclasses Should Override
395 : //////////////////////////////////////////////////////////////////////////////
396 :
397 : /// @return true if this SurfaceFilter can be used with paletted surfaces.
398 0 : virtual bool IsValidPalettedPipe() const { return false; }
399 :
400 : /**
401 : * @return a SurfaceInvalidRect representing the region of the surface that
402 : * has been written to since the last time TakeInvalidRect() was
403 : * called, or Nothing() if the region is empty (i.e. nothing has been
404 : * written).
405 : */
406 : virtual Maybe<SurfaceInvalidRect> TakeInvalidRect() = 0;
407 :
408 : protected:
409 :
410 : /**
411 : * Called by ResetToFirstRow() to actually perform the reset. It's legal to
412 : * throw away any previously written data at this point, as all rows must be
413 : * written to on every pass.
414 : */
415 : virtual uint8_t* DoResetToFirstRow() = 0;
416 :
417 : /**
418 : * Called by AdvanceRow() to actually advance this filter to the next row.
419 : *
420 : * @return a pointer to the buffer for the next row, or nullptr to indicate
421 : * that we've finished the entire surface.
422 : */
423 : virtual uint8_t* DoAdvanceRow() = 0;
424 :
425 :
426 : //////////////////////////////////////////////////////////////////////////////
427 : // Methods For Internal Use By Subclasses
428 : //////////////////////////////////////////////////////////////////////////////
429 :
430 : /**
431 : * Called by subclasses' Configure() methods to initialize the configuration
432 : * of this filter. After the filter is configured, calls ResetToFirstRow().
433 : *
434 : * @param aInputSize The input size of this filter, in pixels. The previous
435 : * filter in the chain will expect to write into rows
436 : * |aInputSize.width| pixels wide.
437 : * @param aPixelSize How large, in bytes, each pixel in the surface is. This
438 : * should be either 1 for paletted images or 4 for BGRA/BGRX
439 : * images.
440 : */
441 51 : void ConfigureFilter(gfx::IntSize aInputSize, uint8_t aPixelSize)
442 : {
443 51 : mInputSize = aInputSize;
444 51 : mPixelSize = aPixelSize;
445 :
446 51 : ResetToFirstRow();
447 51 : }
448 :
449 : private:
450 :
451 : /**
452 : * An internal method used to implement both WritePixels() and
453 : * WritePixelsToRow(). Those methods differ only in their behavior after a row
454 : * is successfully written - WritePixels() continues to write another row,
455 : * while WritePixelsToRow() returns to the caller. This method writes a single
456 : * row and returns Some() if we either finished the entire surface or the
457 : * lambda returned a WriteState indicating that we should return to the
458 : * caller. If the row was successfully written without either of those things
459 : * happening, it returns Nothing(), allowing WritePixels() and
460 : * WritePixelsToRow() to implement their respective behaviors.
461 : */
462 : template <typename PixelType, typename Func>
463 1544 : Maybe<WriteState> DoWritePixelsToRow(Func aFunc)
464 : {
465 1544 : MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
466 1544 : MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
467 1544 : MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
468 :
469 1544 : if (IsSurfaceFinished()) {
470 0 : return Some(WriteState::FINISHED); // We're already done.
471 : }
472 :
473 1540 : PixelType* rowPtr = reinterpret_cast<PixelType*>(mRowPointer);
474 :
475 115996 : for (; mCol < mInputSize.width; ++mCol) {
476 57233 : NextPixel<PixelType> result = aFunc();
477 57240 : if (result.template is<PixelType>()) {
478 57228 : rowPtr[mCol] = result.template as<PixelType>();
479 57151 : continue;
480 : }
481 :
482 1 : switch (result.template as<WriteState>()) {
483 : case WriteState::NEED_MORE_DATA:
484 1 : return Some(WriteState::NEED_MORE_DATA);
485 :
486 : case WriteState::FINISHED:
487 0 : ZeroOutRestOfSurface<PixelType>();
488 0 : return Some(WriteState::FINISHED);
489 :
490 : case WriteState::FAILURE:
491 : // Note that we don't need to record this anywhere, because this
492 : // indicates an error in aFunc, and there's nothing wrong with our
493 : // machinery. The caller can recover as needed and continue writing to
494 : // the row.
495 0 : return Some(WriteState::FAILURE);
496 : }
497 : }
498 :
499 1543 : AdvanceRow(); // We've finished the row.
500 :
501 1542 : return IsSurfaceFinished() ? Some(WriteState::FINISHED)
502 1542 : : Nothing();
503 : }
504 :
505 : template <typename PixelType>
506 0 : void ZeroOutRestOfSurface()
507 : {
508 0 : WritePixels<PixelType>([]{ return AsVariant(PixelType(0)); });
509 0 : }
510 :
511 : gfx::IntSize mInputSize; /// The size of the input this filter expects.
512 : uint8_t* mRowPointer; /// Pointer to the current row or null if finished.
513 : int32_t mCol; /// The current column we're writing to. (0-indexed)
514 : uint8_t mPixelSize; /// How large each pixel in the surface is, in bytes.
515 : };
516 :
517 : class NullSurfaceSink;
518 :
519 : /// A trivial configuration struct for NullSurfaceSink.
520 : struct NullSurfaceConfig
521 : {
522 : using Filter = NullSurfaceSink;
523 : };
524 :
525 : /**
526 : * NullSurfaceSink is a trivial SurfaceFilter implementation that behaves as if
527 : * it were a zero-size SurfaceSink. It's used as the default filter chain for an
528 : * uninitialized SurfacePipe.
529 : *
530 : * To avoid unnecessary allocations when creating SurfacePipe objects,
531 : * NullSurfaceSink is a singleton. (This implies that the implementation must be
532 : * stateless.)
533 : */
534 3 : class NullSurfaceSink final : public SurfaceFilter
535 : {
536 : public:
537 : /// Returns the singleton instance of NullSurfaceSink.
538 : static NullSurfaceSink* Singleton();
539 :
540 0 : virtual ~NullSurfaceSink() { }
541 :
542 : nsresult Configure(const NullSurfaceConfig& aConfig);
543 :
544 0 : Maybe<SurfaceInvalidRect> TakeInvalidRect() override { return Nothing(); }
545 :
546 : protected:
547 3 : uint8_t* DoResetToFirstRow() override { return nullptr; }
548 0 : uint8_t* DoAdvanceRow() override { return nullptr; }
549 :
550 : private:
551 : static UniquePtr<NullSurfaceSink> sSingleton; /// The singleton instance.
552 : };
553 :
554 :
555 : /**
556 : * SurfacePipe is the public API that decoders should use to interact with a
557 : * SurfaceFilter pipeline.
558 : */
559 : class SurfacePipe
560 : {
561 : public:
562 : /// Initialize global state used by all SurfacePipes.
563 3 : static void Initialize() { NullSurfaceSink::Singleton(); }
564 :
565 33 : SurfacePipe()
566 33 : : mHead(NullSurfaceSink::Singleton())
567 33 : { }
568 :
569 145 : SurfacePipe(SurfacePipe&& aOther)
570 145 : : mHead(Move(aOther.mHead))
571 145 : { }
572 :
573 226 : ~SurfacePipe()
574 226 : {
575 : // Ensure that we don't free the NullSurfaceSink singleton.
576 226 : if (mHead.get() == NullSurfaceSink::Singleton()) {
577 19 : Unused << mHead.release();
578 : }
579 226 : }
580 :
581 48 : SurfacePipe& operator=(SurfacePipe&& aOther)
582 : {
583 48 : MOZ_ASSERT(this != &aOther);
584 :
585 : // Ensure that we don't free the NullSurfaceSink singleton.
586 48 : if (mHead.get() == NullSurfaceSink::Singleton()) {
587 14 : Unused << mHead.release();
588 : }
589 :
590 48 : mHead = Move(aOther.mHead);
591 48 : return *this;
592 : }
593 :
594 : /// Begins a new pass, seeking to the first row of the surface.
595 0 : void ResetToFirstRow() { mHead->ResetToFirstRow(); }
596 :
597 : /**
598 : * Write pixels to the surface one at a time by repeatedly calling a lambda
599 : * that yields pixels. WritePixels() is completely memory safe.
600 : *
601 : * @see SurfaceFilter::WritePixels() for the canonical documentation.
602 : */
603 : template <typename PixelType, typename Func>
604 2 : WriteState WritePixels(Func aFunc)
605 : {
606 2 : return mHead->WritePixels<PixelType>(Forward<Func>(aFunc));
607 : }
608 :
609 : /**
610 : * A variant of WritePixels() that writes a single row of pixels to the
611 : * surface one at a time by repeatedly calling a lambda that yields pixels.
612 : * WritePixelsToRow() is completely memory safe.
613 : *
614 : * @see SurfaceFilter::WritePixelsToRow() for the canonical documentation.
615 : */
616 : template <typename PixelType, typename Func>
617 1539 : WriteState WritePixelsToRow(Func aFunc)
618 : {
619 1539 : return mHead->WritePixelsToRow<PixelType>(Forward<Func>(aFunc));
620 : }
621 :
622 : /**
623 : * Write a row to the surface by copying from a buffer. This is bounds checked
624 : * and memory safe with respect to the surface, but care must still be taken
625 : * by the caller not to overread the source buffer. This variant of
626 : * WriteBuffer() requires a source buffer which contains |mInputSize.width|
627 : * pixels.
628 : *
629 : * @see SurfaceFilter::WriteBuffer() for the canonical documentation.
630 : */
631 : template <typename PixelType>
632 : WriteState WriteBuffer(const PixelType* aSource)
633 : {
634 : return mHead->WriteBuffer<PixelType>(aSource);
635 : }
636 :
637 : /**
638 : * Write a row to the surface by copying from a buffer. This is bounds checked
639 : * and memory safe with respect to the surface, but care must still be taken
640 : * by the caller not to overread the source buffer. This variant of
641 : * WriteBuffer() reads at most @aLength pixels from the buffer and writes them
642 : * to the row starting at @aStartColumn. Any pixels in columns before
643 : * @aStartColumn or after the pixels copied from the buffer are cleared.
644 : *
645 : * @see SurfaceFilter::WriteBuffer() for the canonical documentation.
646 : */
647 : template <typename PixelType>
648 : WriteState WriteBuffer(const PixelType* aSource,
649 : const size_t aStartColumn,
650 : const size_t aLength)
651 : {
652 : return mHead->WriteBuffer<PixelType>(aSource, aStartColumn, aLength);
653 : }
654 :
655 : /**
656 : * Write an empty row to the surface. If some pixels have already been written
657 : * to this row, they'll be discarded.
658 : *
659 : * @see SurfaceFilter::WriteEmptyRow() for the canonical documentation.
660 : */
661 : WriteState WriteEmptyRow()
662 : {
663 : return mHead->WriteEmptyRow();
664 : }
665 :
666 : /// @return true if we've finished writing to the surface.
667 : bool IsSurfaceFinished() const { return mHead->IsSurfaceFinished(); }
668 :
669 : /// @see SurfaceFilter::TakeInvalidRect() for the canonical documentation.
670 1538 : Maybe<SurfaceInvalidRect> TakeInvalidRect() const
671 : {
672 1538 : return mHead->TakeInvalidRect();
673 : }
674 :
675 : private:
676 : friend class SurfacePipeFactory;
677 : friend class TestSurfacePipeFactory;
678 :
679 48 : explicit SurfacePipe(UniquePtr<SurfaceFilter>&& aHead)
680 48 : : mHead(Move(aHead))
681 48 : { }
682 :
683 : SurfacePipe(const SurfacePipe&) = delete;
684 : SurfacePipe& operator=(const SurfacePipe&) = delete;
685 :
686 : UniquePtr<SurfaceFilter> mHead; /// The first filter in the chain.
687 : };
688 :
689 : /**
690 : * AbstractSurfaceSink contains shared implementation for both SurfaceSink and
691 : * PalettedSurfaceSink.
692 : */
693 48 : class AbstractSurfaceSink : public SurfaceFilter
694 : {
695 : public:
696 48 : AbstractSurfaceSink()
697 48 : : mImageData(nullptr)
698 : , mImageDataLength(0)
699 : , mRow(0)
700 48 : , mFlipVertically(false)
701 48 : { }
702 :
703 : Maybe<SurfaceInvalidRect> TakeInvalidRect() override final;
704 :
705 : protected:
706 : uint8_t* DoResetToFirstRow() override final;
707 : uint8_t* DoAdvanceRow() override final;
708 : virtual uint8_t* GetRowPointer() const = 0;
709 :
710 : gfx::IntRect mInvalidRect; /// The region of the surface that has been written
711 : /// to since the last call to TakeInvalidRect().
712 : uint8_t* mImageData; /// A pointer to the beginning of the surface data.
713 : uint32_t mImageDataLength; /// The length of the surface data.
714 : uint32_t mRow; /// The row to which we're writing. (0-indexed)
715 : bool mFlipVertically; /// If true, write the rows from top to bottom.
716 : };
717 :
718 : class SurfaceSink;
719 :
720 : /// A configuration struct for SurfaceSink.
721 : struct SurfaceConfig
722 : {
723 : using Filter = SurfaceSink;
724 : Decoder* mDecoder; /// Which Decoder to use to allocate the surface.
725 : uint32_t mFrameNum; /// Which frame of animation this surface is for.
726 : gfx::IntSize mOutputSize; /// The size of the surface.
727 : gfx::SurfaceFormat mFormat; /// The surface format (BGRA or BGRX).
728 : bool mFlipVertically; /// If true, write the rows from bottom to top.
729 : };
730 :
731 : /**
732 : * A sink for normal (i.e., non-paletted) surfaces. It handles the allocation of
733 : * the surface and protects against buffer overflow. This sink should be used
734 : * for all non-animated images and for the first frame of animated images.
735 : *
736 : * Sinks must always be at the end of the SurfaceFilter chain.
737 : */
738 192 : class SurfaceSink final : public AbstractSurfaceSink
739 : {
740 : public:
741 : nsresult Configure(const SurfaceConfig& aConfig);
742 :
743 : protected:
744 : uint8_t* GetRowPointer() const override;
745 : };
746 :
747 : class PalettedSurfaceSink;
748 :
749 : struct PalettedSurfaceConfig
750 : {
751 : using Filter = PalettedSurfaceSink;
752 : Decoder* mDecoder; /// Which Decoder to use to allocate the surface.
753 : uint32_t mFrameNum; /// Which frame of animation this surface is for.
754 : gfx::IntSize mOutputSize; /// The logical size of the surface.
755 : gfx::IntRect mFrameRect; /// The surface subrect which contains data.
756 : gfx::SurfaceFormat mFormat; /// The surface format (BGRA or BGRX).
757 : uint8_t mPaletteDepth; /// The palette depth of this surface.
758 : bool mFlipVertically; /// If true, write the rows from bottom to top.
759 : };
760 :
761 : /**
762 : * A sink for paletted surfaces. It handles the allocation of the surface and
763 : * protects against buffer overflow. This sink can be used for frames of
764 : * animated images except the first.
765 : *
766 : * Sinks must always be at the end of the SurfaceFilter chain.
767 : *
768 : * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
769 : * which means we can remove PalettedSurfaceSink entirely.
770 : */
771 0 : class PalettedSurfaceSink final : public AbstractSurfaceSink
772 : {
773 : public:
774 0 : bool IsValidPalettedPipe() const override { return true; }
775 :
776 : nsresult Configure(const PalettedSurfaceConfig& aConfig);
777 :
778 : protected:
779 : uint8_t* GetRowPointer() const override;
780 :
781 : private:
782 : /**
783 : * The surface subrect which contains data. Note that the surface size we
784 : * actually allocate is the size of the frame rect, not the logical size of
785 : * the surface.
786 : */
787 : gfx::IntRect mFrameRect;
788 : };
789 :
790 : } // namespace image
791 : } // namespace mozilla
792 :
793 : #endif // mozilla_image_SurfacePipe_h
|