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
16class SkSwizzler : public SkSampler {
17public:
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
142private:
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