1 /*
2  * Copyright 2015 The Android Open Source Project
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 SkCodecPriv_DEFINED
9 #define SkCodecPriv_DEFINED
10 
11 #include "SkColorPriv.h"
12 #include "SkColorTable.h"
13 #include "SkImageInfo.h"
14 #include "SkTypes.h"
15 
16 #ifdef SK_PRINT_CODEC_MESSAGES
17     #define SkCodecPrintf SkDebugf
18 #else
19     #define SkCodecPrintf(...)
20 #endif
21 
22 // FIXME: Consider sharing with dm, nanbench, and tools.
get_scale_from_sample_size(int sampleSize)23 inline float get_scale_from_sample_size(int sampleSize) {
24     return 1.0f / ((float) sampleSize);
25 }
26 
is_valid_subset(const SkIRect & subset,const SkISize & imageDims)27 inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) {
28     return SkIRect::MakeSize(imageDims).contains(subset);
29 }
30 
31 /*
32  * returns a scaled dimension based on the original dimension and the sampleSize
33  * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder
34  * FIXME: I think we should call this get_sampled_dimension().
35  */
get_scaled_dimension(int srcDimension,int sampleSize)36 inline int get_scaled_dimension(int srcDimension, int sampleSize) {
37     if (sampleSize > srcDimension) {
38         return 1;
39     }
40     return srcDimension / sampleSize;
41 }
42 
43 /*
44  * Returns the first coordinate that we will keep during a scaled decode.
45  * The output can be interpreted as an x-coordinate or a y-coordinate.
46  *
47  * This does not need to be called and is not called when sampleFactor == 1.
48  */
get_start_coord(int sampleFactor)49 inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; };
50 
51 /*
52  * Given a coordinate in the original image, this returns the corresponding
53  * coordinate in the scaled image.  This function is meaningless if
54  * IsCoordNecessary returns false.
55  * The output can be interpreted as an x-coordinate or a y-coordinate.
56  *
57  * This does not need to be called and is not called when sampleFactor == 1.
58  */
get_dst_coord(int srcCoord,int sampleFactor)59 inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; };
60 
61 /*
62  * When scaling, we will discard certain y-coordinates (rows) and
63  * x-coordinates (columns).  This function returns true if we should keep the
64  * coordinate and false otherwise.
65  * The inputs may be x-coordinates or y-coordinates.
66  *
67  * This does not need to be called and is not called when sampleFactor == 1.
68  */
is_coord_necessary(int srcCoord,int sampleFactor,int scaledDim)69 inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) {
70     // Get the first coordinate that we want to keep
71     int startCoord = get_start_coord(sampleFactor);
72 
73     // Return false on edge cases
74     if (srcCoord < startCoord || get_dst_coord(srcCoord, sampleFactor) >= scaledDim) {
75         return false;
76     }
77 
78     // Every sampleFactor rows are necessary
79     return ((srcCoord - startCoord) % sampleFactor) == 0;
80 }
81 
valid_alpha(SkAlphaType dstAlpha,SkAlphaType srcAlpha)82 inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) {
83     if (kUnknown_SkAlphaType == dstAlpha) {
84         return false;
85     }
86 
87     if (srcAlpha != dstAlpha) {
88         if (kOpaque_SkAlphaType == srcAlpha) {
89             // If the source is opaque, we can support any.
90             SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
91                           "- it is being decoded as non-opaque, which will draw slower\n");
92             return true;
93         }
94 
95         // The source is not opaque
96         switch (dstAlpha) {
97             case kPremul_SkAlphaType:
98             case kUnpremul_SkAlphaType:
99                 // The source is not opaque, so either of these is okay
100                 break;
101             default:
102                 // We cannot decode a non-opaque image to opaque (or unknown)
103                 return false;
104         }
105     }
106     return true;
107 }
108 
109 /*
110  * Most of our codecs support the same conversions:
111  * - profileType must be the same
112  * - opaque to any alpha type
113  * - 565 only if opaque
114  * - premul to unpremul and vice versa
115  * - always support N32
116  * - otherwise match the src color type
117  */
conversion_possible(const SkImageInfo & dst,const SkImageInfo & src)118 inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
119     // FIXME: skbug.com/4895
120     // Currently, we treat both kLinear and ksRGB encoded images as if they are kLinear.
121     // This makes sense while we do not have proper support for ksRGB.  This is also
122     // the reason why we always allow the client to request kLinear.
123     if (dst.profileType() != src.profileType() &&
124             kLinear_SkColorProfileType != dst.profileType()) {
125         return false;
126     }
127 
128     // Ensure the alpha type is valid
129     if (!valid_alpha(dst.alphaType(), src.alphaType())) {
130         return false;
131     }
132 
133     // Check for supported color types
134     switch (dst.colorType()) {
135         case kN32_SkColorType:
136             return true;
137         case kRGB_565_SkColorType:
138             return kOpaque_SkAlphaType == dst.alphaType();
139         case kGray_8_SkColorType:
140             if (kOpaque_SkAlphaType != dst.alphaType()) {
141                 return false;
142             }
143             // Fall through
144         default:
145             return dst.colorType() == src.colorType();
146     }
147 }
148 
149 /*
150  * If there is a color table, get a pointer to the colors, otherwise return nullptr
151  */
get_color_ptr(SkColorTable * colorTable)152 inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) {
153      return nullptr != colorTable ? colorTable->readColors() : nullptr;
154 }
155 
156 /*
157  * Given that the encoded image uses a color table, return the fill value
158  */
get_color_table_fill_value(SkColorType colorType,const SkPMColor * colorPtr,uint8_t fillIndex)159 inline uint32_t get_color_table_fill_value(SkColorType colorType, const SkPMColor* colorPtr,
160         uint8_t fillIndex) {
161     SkASSERT(nullptr != colorPtr);
162     switch (colorType) {
163         case kN32_SkColorType:
164             return colorPtr[fillIndex];
165         case kRGB_565_SkColorType:
166             return SkPixel32ToPixel16(colorPtr[fillIndex]);
167         case kIndex_8_SkColorType:
168             return fillIndex;
169         default:
170             SkASSERT(false);
171             return 0;
172     }
173 }
174 
175 /*
176  *
177  * Copy the codec color table back to the client when kIndex8 color type is requested
178  */
copy_color_table(const SkImageInfo & dstInfo,SkColorTable * colorTable,SkPMColor * inputColorPtr,int * inputColorCount)179 inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable,
180         SkPMColor* inputColorPtr, int* inputColorCount) {
181     if (kIndex_8_SkColorType == dstInfo.colorType()) {
182         SkASSERT(nullptr != inputColorPtr);
183         SkASSERT(nullptr != inputColorCount);
184         SkASSERT(nullptr != colorTable);
185         memcpy(inputColorPtr, colorTable->readColors(), *inputColorCount * sizeof(SkPMColor));
186     }
187 }
188 
189 /*
190  * Compute row bytes for an image using pixels per byte
191  */
compute_row_bytes_ppb(int width,uint32_t pixelsPerByte)192 inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) {
193     return (width + pixelsPerByte - 1) / pixelsPerByte;
194 }
195 
196 /*
197  * Compute row bytes for an image using bytes per pixel
198  */
compute_row_bytes_bpp(int width,uint32_t bytesPerPixel)199 inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) {
200     return width * bytesPerPixel;
201 }
202 
203 /*
204  * Compute row bytes for an image
205  */
compute_row_bytes(int width,uint32_t bitsPerPixel)206 inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) {
207     if (bitsPerPixel < 16) {
208         SkASSERT(0 == 8 % bitsPerPixel);
209         const uint32_t pixelsPerByte = 8 / bitsPerPixel;
210         return compute_row_bytes_ppb(width, pixelsPerByte);
211     } else {
212         SkASSERT(0 == bitsPerPixel % 8);
213         const uint32_t bytesPerPixel = bitsPerPixel / 8;
214         return compute_row_bytes_bpp(width, bytesPerPixel);
215     }
216 }
217 
218 /*
219  * Get a byte from a buffer
220  * This method is unsafe, the caller is responsible for performing a check
221  */
get_byte(uint8_t * buffer,uint32_t i)222 inline uint8_t get_byte(uint8_t* buffer, uint32_t i) {
223     return buffer[i];
224 }
225 
226 /*
227  * Get a short from a buffer
228  * This method is unsafe, the caller is responsible for performing a check
229  */
get_short(uint8_t * buffer,uint32_t i)230 inline uint16_t get_short(uint8_t* buffer, uint32_t i) {
231     uint16_t result;
232     memcpy(&result, &(buffer[i]), 2);
233 #ifdef SK_CPU_BENDIAN
234     return SkEndianSwap16(result);
235 #else
236     return result;
237 #endif
238 }
239 
240 /*
241  * Get an int from a buffer
242  * This method is unsafe, the caller is responsible for performing a check
243  */
get_int(uint8_t * buffer,uint32_t i)244 inline uint32_t get_int(uint8_t* buffer, uint32_t i) {
245     uint32_t result;
246     memcpy(&result, &(buffer[i]), 4);
247 #ifdef SK_CPU_BENDIAN
248     return SkEndianSwap32(result);
249 #else
250     return result;
251 #endif
252 }
253 
254 #endif // SkCodecPriv_DEFINED
255