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