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