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.
23inline float get_scale_from_sample_size(int sampleSize) {
24    return 1.0f / ((float) sampleSize);
25}
26
27inline 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 */
36inline 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 */
49inline 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 */
59inline 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 */
69inline 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
82inline 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 */
118inline 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 */
152inline 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 */
159inline 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 */
179inline 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 */
192inline 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 */
199inline 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 */
206inline 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 */
222inline 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 */
230inline 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 */
244inline 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