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 SkSwizzler_DEFINED
      9 #define SkSwizzler_DEFINED
     10 
     11 #include "SkCodec.h"
     12 #include "SkColor.h"
     13 #include "SkImageInfo.h"
     14 #include "SkSampler.h"
     15 
     16 class SkSwizzler : public SkSampler {
     17 public:
     18     /**
     19      *  Enum describing the config of the source data.
     20      */
     21     enum SrcConfig {
     22         kUnknown,  // Invalid type.
     23         kBit,      // A single bit to distinguish between white and black.
     24         kGray,
     25         kGrayAlpha,
     26         kIndex1,
     27         kIndex2,
     28         kIndex4,
     29         kIndex,
     30         kRGB,
     31         kBGR,
     32         kBGRX,     // The alpha channel can be anything, but the image is opaque.
     33         kRGBA,
     34         kBGRA,
     35         kCMYK,
     36         kNoOp8,    // kNoOp modes are used exclusively for sampling, subsetting, and
     37         kNoOp16,   // copying.  The pixels themselves do not need to be modified.
     38         kNoOp32,
     39     };
     40 
     41     /*
     42      *
     43      * Returns bits per pixel for source config
     44      *
     45      */
     46     static int BitsPerPixel(SrcConfig sc) {
     47         switch (sc) {
     48             case kBit:
     49             case kIndex1:
     50                 return 1;
     51             case kIndex2:
     52                 return 2;
     53             case kIndex4:
     54                 return 4;
     55             case kGray:
     56             case kIndex:
     57             case kNoOp8:
     58                 return 8;
     59             case kGrayAlpha:
     60             case kNoOp16:
     61                 return 16;
     62             case kRGB:
     63             case kBGR:
     64                 return 24;
     65             case kRGBA:
     66             case kBGRX:
     67             case kBGRA:
     68             case kCMYK:
     69             case kNoOp32:
     70                 return 32;
     71             default:
     72                 SkASSERT(false);
     73                 return 0;
     74         }
     75     }
     76 
     77     /*
     78      *
     79      * Returns bytes per pixel for source config
     80      * Raises an error if each pixel is not stored in an even number of bytes
     81      *
     82      */
     83     static int BytesPerPixel(SrcConfig sc) {
     84         SkASSERT(SkIsAlign8(BitsPerPixel(sc)));
     85         return BitsPerPixel(sc) >> 3;
     86     }
     87 
     88     /**
     89      *  Create a new SkSwizzler.
     90      *  @param SrcConfig Description of the format of the source.
     91      *  @param ctable Unowned pointer to an array of up to 256 colors for an
     92      *                index source.
     93      *  @param dstInfo Describes the destination.
     94      *  @param options Indicates if dst is zero-initialized. The
     95      *                         implementation may choose to skip writing zeroes
     96      *                         if set to kYes_ZeroInitialized.
     97      *                 Contains partial scanline information.
     98      *  @param frame   Is non-NULL if the source pixels are part of an image
     99      *                 frame that is a subset of the full image.
    100      *
    101      *  Note that a deeper discussion of partial scanline subsets and image frame
    102      *  subsets is below.  Currently, we do not support both simultaneously.  If
    103      *  options->fSubset is non-NULL, frame must be NULL.
    104      *
    105      *  @return A new SkSwizzler or nullptr on failure.
    106      */
    107     static SkSwizzler* CreateSwizzler(SrcConfig, const SkPMColor* ctable,
    108                                       const SkImageInfo& dstInfo, const SkCodec::Options&,
    109                                       const SkIRect* frame = nullptr);
    110 
    111     /**
    112      *  Swizzle a line. Generally this will be called height times, once
    113      *  for each row of source.
    114      *  By allowing the caller to pass in the dst pointer, we give the caller
    115      *  flexibility to use the swizzler even when the encoded data does not
    116      *  store the rows in order.  This also improves usability for scaled and
    117      *  subset decodes.
    118      *  @param dst Where we write the output.
    119      *  @param src The next row of the source data.
    120      */
    121     void swizzle(void* dst, const uint8_t* SK_RESTRICT src);
    122 
    123     /**
    124      * Implement fill using a custom width.
    125      */
    126     void fill(const SkImageInfo& info, void* dst, size_t rowBytes, uint32_t colorOrIndex,
    127             SkCodec::ZeroInitialized zeroInit) override {
    128         const SkImageInfo fillInfo = info.makeWH(fAllocatedWidth, info.height());
    129         SkSampler::Fill(fillInfo, dst, rowBytes, colorOrIndex, zeroInit);
    130     }
    131 
    132     /**
    133      *  If fSampleX > 1, the swizzler is sampling every fSampleX'th pixel and
    134      *  discarding the rest.
    135      *
    136      *  This getter is currently used by SkBmpStandardCodec for Bmp-in-Ico decodes.
    137      *  Ideally, the subclasses of SkCodec would have no knowledge of sampling, but
    138      *  this allows us to apply a transparency mask to pixels after swizzling.
    139      */
    140     int sampleX() const { return fSampleX; }
    141 
    142 private:
    143 
    144     /**
    145      *  Method for converting raw data to Skia pixels.
    146      *  @param dstRow Row in which to write the resulting pixels.
    147      *  @param src Row of src data, in format specified by SrcConfig
    148      *  @param dstWidth Width in pixels of the destination
    149      *  @param bpp if bitsPerPixel % 8 == 0, deltaSrc is bytesPerPixel
    150      *             else, deltaSrc is bitsPerPixel
    151      *  @param deltaSrc bpp * sampleX
    152      *  @param ctable Colors (used for kIndex source).
    153      *  @param offset The offset before the first pixel to sample.
    154                         Is in bytes or bits based on what deltaSrc is in.
    155      */
    156     typedef void (*RowProc)(void* SK_RESTRICT dstRow,
    157                             const uint8_t* SK_RESTRICT src,
    158                             int dstWidth, int bpp, int deltaSrc, int offset,
    159                             const SkPMColor ctable[]);
    160 
    161     template <RowProc Proc>
    162     static void SkipLeading8888ZerosThen(void* SK_RESTRICT dstRow,
    163                                          const uint8_t* SK_RESTRICT src,
    164                                          int dstWidth, int bpp, int deltaSrc, int offset,
    165                                          const SkPMColor ctable[]);
    166 
    167     template <RowProc Proc>
    168     static void SkipLeadingGrayAlphaZerosThen(void* dst, const uint8_t* src, int width, int bpp,
    169                                               int deltaSrc, int offset, const SkPMColor ctable[]);
    170 
    171     // May be NULL.  We have not implemented optimized functions for all supported transforms.
    172     const RowProc       fFastProc;
    173     // Always non-NULL.  Supports sampling.
    174     const RowProc       fSlowProc;
    175     // The actual RowProc we are using.  This depends on if fFastProc is non-NULL and
    176     // whether or not we are sampling.
    177     RowProc             fActualProc;
    178 
    179     const SkPMColor*    fColorTable;      // Unowned pointer
    180 
    181     // Subset Swizzles
    182     // There are two types of subset swizzles that we support.  We do not
    183     // support both at the same time.
    184     // TODO: If we want to support partial scanlines for gifs (which may
    185     //       use frame subsets), we will need to support both subsetting
    186     //       modes at the same time.
    187     // (1) Partial Scanlines
    188     //         The client only wants to write a subset of the source pixels
    189     //         to the destination.  This subset is specified to CreateSwizzler
    190     //         using options->fSubset.  We will store subset information in
    191     //         the following fields.
    192     //
    193     //         fSrcOffset:      The starting pixel of the source.
    194     //         fSrcOffsetUnits: Derived from fSrcOffset with two key
    195     //                          differences:
    196     //                          (1) This takes the size of source pixels into
    197     //                          account by multiplying by fSrcBPP.  This may
    198     //                          be measured in bits or bytes depending on
    199     //                          which is natural for the SrcConfig.
    200     //                          (2) If we are sampling, this will be larger
    201     //                          than fSrcOffset * fSrcBPP, since sampling
    202     //                          implies that we will skip some pixels.
    203     //         fDstOffset:      Will be zero.  There is no destination offset
    204     //                          for this type of subset.
    205     //         fDstOffsetBytes: Will be zero.
    206     //         fSrcWidth:       The width of the desired subset of source
    207     //                          pixels, before any sampling is performed.
    208     //         fDstWidth:       Will be equal to fSrcWidth, since this is also
    209     //                          calculated before any sampling is performed.
    210     //                          For this type of subset, the destination width
    211     //                          matches the desired subset of the source.
    212     //         fSwizzleWidth:   The actual number of pixels that will be
    213     //                          written by the RowProc.  This is a scaled
    214     //                          version of fSrcWidth/fDstWidth.
    215     //         fAllocatedWidth: Will be equal to fSwizzleWidth.  For this type
    216     //                          of subset, the number of pixels written is the
    217     //                          same as the actual width of the destination.
    218     // (2) Frame Subset
    219     //         The client will decode the entire width of the source into a
    220     //         subset of destination memory.  This subset is specified to
    221     //         CreateSwizzler in the "frame" parameter.  We store subset
    222     //         information in the following fields.
    223     //
    224     //         fSrcOffset:      Will be zero.  The starting pixel of the source.
    225     //         fSrcOffsetUnits: Will only be non-zero if we are sampling,
    226     //                          since sampling implies that we will skip some
    227     //                          pixels.  Note that this is measured in bits
    228     //                          or bytes depending on which is natural for
    229     //                          SrcConfig.
    230     //         fDstOffset:      First pixel to write in destination.
    231     //         fDstOffsetBytes: fDstOffset * fDstBPP.
    232     //         fSrcWidth:       The entire width of the source pixels, before
    233     //                          any sampling is performed.
    234     //         fDstWidth:       The entire width of the destination memory,
    235     //                          before any sampling is performed.
    236     //         fSwizzleWidth:   The actual number of pixels that will be
    237     //                          written by the RowProc.  This is a scaled
    238     //                          version of fSrcWidth.
    239     //         fAllocatedWidth: The actual number of pixels in destination
    240     //                          memory.  This is a scaled version of
    241     //                          fDstWidth.
    242     //
    243     // If we are not subsetting, these fields are more straightforward.
    244     //         fSrcOffset = fDstOffet = fDstOffsetBytes = 0
    245     //         fSrcOffsetUnits may be non-zero (we will skip the first few pixels when sampling)
    246     //         fSrcWidth = fDstWidth = Full original width
    247     //         fSwizzleWidth = fAllcoatedWidth = Scaled width (if we are sampling)
    248     const int           fSrcOffset;
    249     const int           fDstOffset;
    250     int                 fSrcOffsetUnits;
    251     int                 fDstOffsetBytes;
    252     const int           fSrcWidth;
    253     const int           fDstWidth;
    254     int                 fSwizzleWidth;
    255     int                 fAllocatedWidth;
    256 
    257     int                 fSampleX;         // Step between X samples
    258     const int           fSrcBPP;          // Bits/bytes per pixel for the SrcConfig
    259                                           // if bitsPerPixel % 8 == 0
    260                                           //     fBPP is bytesPerPixel
    261                                           // else
    262                                           //     fBPP is bitsPerPixel
    263     const int           fDstBPP;          // Bytes per pixel for the destination color type
    264 
    265     SkSwizzler(RowProc fastProc, RowProc proc, const SkPMColor* ctable, int srcOffset,
    266             int srcWidth, int dstOffset, int dstWidth, int srcBPP, int dstBPP);
    267 
    268     int onSetSampleX(int) override;
    269 
    270 };
    271 #endif // SkSwizzler_DEFINED
    272