Home | History | Annotate | Download | only in codec
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef SkScanlineDecoder_DEFINED
      9 #define SkScanlineDecoder_DEFINED
     10 
     11 #include "SkTypes.h"
     12 #include "SkTemplates.h"
     13 #include "SkImageGenerator.h"
     14 #include "SkImageInfo.h"
     15 
     16 class SkScanlineDecoder : public SkNoncopyable {
     17 public:
     18     // Note for implementations: An SkScanlineDecoder will be deleted by (and
     19     // therefore *before*) its associated SkCodec, in case the order matters.
     20     virtual ~SkScanlineDecoder() {}
     21 
     22     /**
     23      *  Write the next countLines scanlines into dst.
     24      *
     25      *  @param dst Must be non-null, and large enough to hold countLines
     26      *      scanlines of size rowBytes.
     27      *  @param countLines Number of lines to write.
     28      *  @param rowBytes Number of bytes per row. Must be large enough to hold
     29      *      a scanline based on the SkImageInfo used to create this object.
     30      */
     31     SkImageGenerator::Result getScanlines(void* dst, int countLines, size_t rowBytes) {
     32         if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines <= 0
     33                 || fCurrScanline + countLines > fDstInfo.height()) {
     34             return SkImageGenerator::kInvalidParameters;
     35         }
     36         const SkImageGenerator::Result result = this->onGetScanlines(dst, countLines, rowBytes);
     37         this->checkForFinish(countLines);
     38         return result;
     39     }
     40 
     41     /**
     42      *  Skip count scanlines.
     43      *
     44      *  The default version just calls onGetScanlines and discards the dst.
     45      *  NOTE: If skipped lines are the only lines with alpha, this default
     46      *  will make reallyHasAlpha return true, when it could have returned
     47      *  false.
     48      */
     49     SkImageGenerator::Result skipScanlines(int countLines) {
     50         if (fCurrScanline + countLines > fDstInfo.height()) {
     51             // Arguably, we could just skip the scanlines which are remaining,
     52             // and return kSuccess. We choose to return invalid so the client
     53             // can catch their bug.
     54             return SkImageGenerator::kInvalidParameters;
     55         }
     56         const SkImageGenerator::Result result = this->onSkipScanlines(countLines);
     57         this->checkForFinish(countLines);
     58         return result;
     59     }
     60 
     61     /**
     62      *  Some images may initially report that they have alpha due to the format
     63      *  of the encoded data, but then never use any colors which have alpha
     64      *  less than 100%. This function can be called *after* decoding to
     65      *  determine if such an image truly had alpha. Calling it before decoding
     66      *  is undefined.
     67      *  FIXME: see skbug.com/3582.
     68      */
     69     bool reallyHasAlpha() const {
     70         return this->onReallyHasAlpha();
     71     }
     72 
     73 protected:
     74     SkScanlineDecoder(const SkImageInfo& requested)
     75         : fDstInfo(requested)
     76         , fCurrScanline(0) {}
     77 
     78     virtual bool onReallyHasAlpha() const { return false; }
     79 
     80     const SkImageInfo& dstInfo() const { return fDstInfo; }
     81 
     82 private:
     83     const SkImageInfo   fDstInfo;
     84     int                 fCurrScanline;
     85 
     86     // Naive default version just calls onGetScanlines on temp memory.
     87     virtual SkImageGenerator::Result onSkipScanlines(int countLines) {
     88         SkAutoMalloc storage(fDstInfo.minRowBytes());
     89         // Note that we pass 0 to rowBytes so we continue to use the same memory.
     90         // Also note that while getScanlines checks that rowBytes is big enough,
     91         // onGetScanlines bypasses that check.
     92         // Calling the virtual method also means we do not double count
     93         // countLines.
     94         return this->onGetScanlines(storage.get(), countLines, 0);
     95     }
     96 
     97     virtual SkImageGenerator::Result onGetScanlines(void* dst, int countLines,
     98                                                     size_t rowBytes) = 0;
     99 
    100     /**
    101      *  Called after any set of scanlines read/skipped. Updates fCurrScanline,
    102      *  and, if we are at the end, calls onFinish().
    103      */
    104     void checkForFinish(int countLines) {
    105         fCurrScanline += countLines;
    106         if (fCurrScanline >= fDstInfo.height()) {
    107             this->onFinish();
    108         }
    109     }
    110 
    111     /**
    112      *  This function will be called after reading/skipping all scanlines to do
    113      *  any necessary cleanups.
    114      */
    115     virtual void onFinish() {} // Default does nothing.
    116 };
    117 #endif // SkScanlineDecoder_DEFINED
    118