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 */ BitsPerPixel(SrcConfig sc)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 */ BytesPerPixel(SrcConfig sc)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 */ fill(const SkImageInfo & info,void * dst,size_t rowBytes,uint32_t colorOrIndex,SkCodec::ZeroInitialized zeroInit)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 */ sampleX()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