blob: 9c215c6dd4aae3f28d37ac9d1d1213908f81a99d [file] [log] [blame]
scroggof24f2242015-03-03 08:59:20 -08001/*
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 SkCodec_DEFINED
9#define SkCodec_DEFINED
10
bungemanf3c15b72015-08-19 11:56:48 -070011#include "../private/SkTemplates.h"
Leon Scroggins IIIc8037dc2017-12-05 13:55:24 -050012#include "../private/SkEncodedInfo.h"
Leon Scroggins III33deb7e2017-06-07 12:31:51 -040013#include "SkCodecAnimation.h"
scroggoeb602a52015-07-09 08:16:03 -070014#include "SkColor.h"
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -040015#include "SkColorSpaceXform.h"
Hal Canarydb683012016-11-23 08:55:18 -070016#include "SkEncodedImageFormat.h"
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -040017#include "SkEncodedOrigin.h"
scroggof24f2242015-03-03 08:59:20 -080018#include "SkImageInfo.h"
Mike Reed43798692017-10-17 18:04:32 +000019#include "SkPixmap.h"
scroggof24f2242015-03-03 08:59:20 -080020#include "SkSize.h"
scroggofffeede2015-03-18 10:50:37 -070021#include "SkStream.h"
scroggof24f2242015-03-03 08:59:20 -080022#include "SkTypes.h"
msarett4984c3c2016-03-10 05:44:43 -080023#include "SkYUVSizeInfo.h"
scroggof24f2242015-03-03 08:59:20 -080024
scroggo19b91532016-10-24 09:03:26 -070025#include <vector>
26
msarettad8bcfe2016-03-07 07:09:03 -080027class SkColorSpace;
scroggof24f2242015-03-03 08:59:20 -080028class SkData;
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -040029class SkFrameHolder;
scroggocf98fa92015-11-23 08:14:40 -080030class SkPngChunkReader;
scroggoe7fc14b2015-10-02 13:14:46 -070031class SkSampler;
scroggof24f2242015-03-03 08:59:20 -080032
msarett9876ac52016-06-01 14:47:18 -070033namespace DM {
scroggo8e6c7ad2016-09-16 08:20:38 -070034class CodecSrc;
msarett9876ac52016-06-01 14:47:18 -070035class ColorCodecSrc;
36}
msarett2cee9022016-06-03 08:25:21 -070037class ColorCodecBench;
msarett9876ac52016-06-01 14:47:18 -070038
scroggof24f2242015-03-03 08:59:20 -080039/**
40 * Abstraction layer directly on top of an image codec.
41 */
Florin Malita78c212a2016-12-14 13:17:01 -050042class SK_API SkCodec : SkNoncopyable {
scroggof24f2242015-03-03 08:59:20 -080043public:
44 /**
scroggodb30be22015-12-08 18:54:13 -080045 * Minimum number of bytes that must be buffered in SkStream input.
46 *
47 * An SkStream passed to NewFromStream must be able to use this many
48 * bytes to determine the image type. Then the same SkStream must be
49 * passed to the correct decoder to read from the beginning.
50 *
51 * This can be accomplished by implementing peek() to support peeking
52 * this many bytes, or by implementing rewind() to be able to rewind()
53 * after reading this many bytes.
54 */
Leon Scroggins III04be2b52017-08-17 15:13:20 -040055 static constexpr size_t MinBufferedBytesNeeded() { return 32; }
scroggodb30be22015-12-08 18:54:13 -080056
57 /**
Leon Scroggins III588fb042017-07-14 16:32:31 -040058 * Error codes for various SkCodec methods.
59 */
60 enum Result {
61 /**
62 * General return value for success.
63 */
64 kSuccess,
65 /**
66 * The input is incomplete. A partial image was generated.
67 */
68 kIncompleteInput,
69 /**
70 * Like kIncompleteInput, except the input had an error.
71 *
72 * If returned from an incremental decode, decoding cannot continue,
73 * even with more data.
74 */
75 kErrorInInput,
76 /**
77 * The generator cannot convert to match the request, ignoring
78 * dimensions.
79 */
80 kInvalidConversion,
81 /**
82 * The generator cannot scale to requested size.
83 */
84 kInvalidScale,
85 /**
86 * Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes
87 * too small, etc.
88 */
89 kInvalidParameters,
90 /**
91 * The input did not contain a valid image.
92 */
93 kInvalidInput,
94 /**
95 * Fulfilling this request requires rewinding the input, which is not
96 * supported for this input.
97 */
98 kCouldNotRewind,
99 /**
100 * An internal error, such as OOM.
101 */
102 kInternalError,
103 /**
104 * This method is not implemented by this codec.
105 * FIXME: Perhaps this should be kUnsupported?
106 */
107 kUnimplemented,
108 };
109
110 /**
Leon Scroggins IIIfe3da022018-01-16 11:56:54 -0500111 * Readable string representing the error code.
112 */
113 static const char* ResultToString(Result);
114
115 /**
scroggof24f2242015-03-03 08:59:20 -0800116 * If this stream represents an encoded image that we know how to decode,
117 * return an SkCodec that can decode it. Otherwise return NULL.
118 *
scroggodb30be22015-12-08 18:54:13 -0800119 * As stated above, this call must be able to peek or read
120 * MinBufferedBytesNeeded to determine the correct format, and then start
121 * reading from the beginning. First it will attempt to peek, and it
122 * assumes that if less than MinBufferedBytesNeeded bytes (but more than
123 * zero) are returned, this is because the stream is shorter than this,
124 * so falling back to reading would not provide more data. If peek()
125 * returns zero bytes, this call will instead attempt to read(). This
126 * will require that the stream can be rewind()ed.
127 *
Leon Scroggins III588fb042017-07-14 16:32:31 -0400128 * If Result is not NULL, it will be set to either kSuccess if an SkCodec
129 * is returned or a reason for the failure if NULL is returned.
130 *
scroggodb30be22015-12-08 18:54:13 -0800131 * If SkPngChunkReader is not NULL, take a ref and pass it to libpng if
132 * the image is a png.
133 *
msarett7d5105c2015-12-02 07:02:41 -0800134 * If the SkPngChunkReader is not NULL then:
135 * If the image is not a PNG, the SkPngChunkReader will be ignored.
136 * If the image is a PNG, the SkPngChunkReader will be reffed.
137 * If the PNG has unknown chunks, the SkPngChunkReader will be used
138 * to handle these chunks. SkPngChunkReader will be called to read
139 * any unknown chunk at any point during the creation of the codec
140 * or the decode. Note that if SkPngChunkReader fails to read a
141 * chunk, this could result in a failure to create the codec or a
142 * failure to decode the image.
143 * If the PNG does not contain unknown chunks, the SkPngChunkReader
144 * will not be used or modified.
scroggocf98fa92015-11-23 08:14:40 -0800145 *
scroggof24f2242015-03-03 08:59:20 -0800146 * If NULL is returned, the stream is deleted immediately. Otherwise, the
147 * SkCodec takes ownership of it, and will delete it when done with it.
148 */
Mike Reedede7bac2017-07-23 15:30:02 -0400149 static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result* = nullptr,
150 SkPngChunkReader* = nullptr);
scroggof24f2242015-03-03 08:59:20 -0800151
152 /**
153 * If this data represents an encoded image that we know how to decode,
154 * return an SkCodec that can decode it. Otherwise return NULL.
155 *
msarett7d5105c2015-12-02 07:02:41 -0800156 * If the SkPngChunkReader is not NULL then:
157 * If the image is not a PNG, the SkPngChunkReader will be ignored.
158 * If the image is a PNG, the SkPngChunkReader will be reffed.
159 * If the PNG has unknown chunks, the SkPngChunkReader will be used
160 * to handle these chunks. SkPngChunkReader will be called to read
161 * any unknown chunk at any point during the creation of the codec
162 * or the decode. Note that if SkPngChunkReader fails to read a
163 * chunk, this could result in a failure to create the codec or a
164 * failure to decode the image.
165 * If the PNG does not contain unknown chunks, the SkPngChunkReader
166 * will not be used or modified.
scroggof24f2242015-03-03 08:59:20 -0800167 */
Mike Reedede7bac2017-07-23 15:30:02 -0400168 static std::unique_ptr<SkCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr);
169
scroggoeb602a52015-07-09 08:16:03 -0700170 virtual ~SkCodec();
171
172 /**
173 * Return the ImageInfo associated with this codec.
174 */
scroggo46c57472015-09-30 08:57:13 -0700175 const SkImageInfo& getInfo() const { return fSrcInfo; }
scroggoeb602a52015-07-09 08:16:03 -0700176
msarett0e6274f2016-03-21 08:04:40 -0700177 /**
178 * Returns the image orientation stored in the EXIF data.
179 * If there is no EXIF data, or if we cannot read the EXIF data, returns kTopLeft.
180 */
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -0400181 SkEncodedOrigin getOrigin() const { return fOrigin; }
msarett0e6274f2016-03-21 08:04:40 -0700182
msarett6a738212016-03-04 13:27:35 -0800183 /**
scroggof24f2242015-03-03 08:59:20 -0800184 * Return a size that approximately supports the desired scale factor.
185 * The codec may not be able to scale efficiently to the exact scale
186 * factor requested, so return a size that approximates that scale.
emmaleer8f4ba762015-08-14 07:44:46 -0700187 * The returned value is the codec's suggestion for the closest valid
188 * scale that it can natively support
scroggof24f2242015-03-03 08:59:20 -0800189 */
scroggofffeede2015-03-18 10:50:37 -0700190 SkISize getScaledDimensions(float desiredScale) const {
msarettb32758a2015-08-18 13:22:46 -0700191 // Negative and zero scales are errors.
192 SkASSERT(desiredScale > 0.0f);
193 if (desiredScale <= 0.0f) {
194 return SkISize::Make(0, 0);
195 }
196
197 // Upscaling is not supported. Return the original size if the client
198 // requests an upscale.
199 if (desiredScale >= 1.0f) {
200 return this->getInfo().dimensions();
201 }
scroggofffeede2015-03-18 10:50:37 -0700202 return this->onGetScaledDimensions(desiredScale);
203 }
scroggof24f2242015-03-03 08:59:20 -0800204
scroggo1dd3ea92015-03-20 11:55:55 -0700205 /**
scroggob636b452015-07-22 07:16:20 -0700206 * Return (via desiredSubset) a subset which can decoded from this codec,
207 * or false if this codec cannot decode subsets or anything similar to
208 * desiredSubset.
209 *
210 * @param desiredSubset In/out parameter. As input, a desired subset of
211 * the original bounds (as specified by getInfo). If true is returned,
212 * desiredSubset may have been modified to a subset which is
213 * supported. Although a particular change may have been made to
214 * desiredSubset to create something supported, it is possible other
215 * changes could result in a valid subset.
216 * If false is returned, desiredSubset's value is undefined.
217 * @return true if this codec supports decoding desiredSubset (as
218 * returned, potentially modified)
219 */
220 bool getValidSubset(SkIRect* desiredSubset) const {
221 return this->onGetValidSubset(desiredSubset);
222 }
223
224 /**
scroggo1dd3ea92015-03-20 11:55:55 -0700225 * Format of the encoded data.
226 */
Hal Canarydb683012016-11-23 08:55:18 -0700227 SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); }
scroggo1dd3ea92015-03-20 11:55:55 -0700228
scroggo05245902015-03-25 11:11:52 -0700229 /**
scroggoeb602a52015-07-09 08:16:03 -0700230 * Whether or not the memory passed to getPixels is zero initialized.
231 */
232 enum ZeroInitialized {
233 /**
234 * The memory passed to getPixels is zero initialized. The SkCodec
235 * may take advantage of this by skipping writing zeroes.
236 */
237 kYes_ZeroInitialized,
238 /**
239 * The memory passed to getPixels has not been initialized to zero,
240 * so the SkCodec must write all zeroes to memory.
241 *
242 * This is the default. It will be used if no Options struct is used.
243 */
244 kNo_ZeroInitialized,
245 };
246
247 /**
248 * Additional options to pass to getPixels.
249 */
250 struct Options {
251 Options()
scroggob636b452015-07-22 07:16:20 -0700252 : fZeroInitialized(kNo_ZeroInitialized)
scroggo19b91532016-10-24 09:03:26 -0700253 , fSubset(nullptr)
254 , fFrameIndex(0)
Leon Scroggins III33deb7e2017-06-07 12:31:51 -0400255 , fPriorFrame(kNone)
Matt Sarettcf3f2342017-03-23 15:32:25 -0400256 , fPremulBehavior(SkTransferFunctionBehavior::kRespect)
scroggob636b452015-07-22 07:16:20 -0700257 {}
scroggoeb602a52015-07-09 08:16:03 -0700258
Matt Sarettcf3f2342017-03-23 15:32:25 -0400259 ZeroInitialized fZeroInitialized;
scroggob636b452015-07-22 07:16:20 -0700260 /**
261 * If not NULL, represents a subset of the original image to decode.
scroggob636b452015-07-22 07:16:20 -0700262 * Must be within the bounds returned by getInfo().
Hal Canarydb683012016-11-23 08:55:18 -0700263 * If the EncodedFormat is SkEncodedImageFormat::kWEBP (the only one which
scroggob636b452015-07-22 07:16:20 -0700264 * currently supports subsets), the top and left values must be even.
msarettfdb47572015-10-13 12:50:14 -0700265 *
scroggo8e6c7ad2016-09-16 08:20:38 -0700266 * In getPixels and incremental decode, we will attempt to decode the
267 * exact rectangular subset specified by fSubset.
msarettfdb47572015-10-13 12:50:14 -0700268 *
269 * In a scanline decode, it does not make sense to specify a subset
270 * top or subset height, since the client already controls which rows
271 * to get and which rows to skip. During scanline decodes, we will
272 * require that the subset top be zero and the subset height be equal
273 * to the full height. We will, however, use the values of
274 * subset left and subset width to decode partial scanlines on calls
275 * to getScanlines().
scroggob636b452015-07-22 07:16:20 -0700276 */
Matt Sarettcf3f2342017-03-23 15:32:25 -0400277 const SkIRect* fSubset;
scroggo19b91532016-10-24 09:03:26 -0700278
279 /**
280 * The frame to decode.
281 *
282 * Only meaningful for multi-frame images.
283 */
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400284 int fFrameIndex;
scroggo19b91532016-10-24 09:03:26 -0700285
286 /**
Leon Scroggins III33deb7e2017-06-07 12:31:51 -0400287 * If not kNone, the dst already contains the prior frame at this index.
scroggo19b91532016-10-24 09:03:26 -0700288 *
289 * Only meaningful for multi-frame images.
290 *
291 * If fFrameIndex needs to be blended with a prior frame (as reported by
292 * getFrameInfo[fFrameIndex].fRequiredFrame), the client can set this to
Leon Scroggins III33deb7e2017-06-07 12:31:51 -0400293 * any non-kRestorePrevious frame in [fRequiredFrame, fFrameIndex) to
294 * indicate that that frame is already in the dst. Options.fZeroInitialized
295 * is ignored in this case.
scroggo19b91532016-10-24 09:03:26 -0700296 *
Leon Scroggins III33deb7e2017-06-07 12:31:51 -0400297 * If set to kNone, the codec will decode any necessary required frame(s) first.
scroggo19b91532016-10-24 09:03:26 -0700298 */
Leon Scroggins III33deb7e2017-06-07 12:31:51 -0400299 int fPriorFrame;
Matt Sarettcf3f2342017-03-23 15:32:25 -0400300
301 /**
302 * Indicates whether we should do a linear premultiply or a legacy premultiply.
303 *
304 * In the case where the dst SkColorSpace is nullptr, this flag is ignored and
305 * we will always do a legacy premultiply.
306 */
307 SkTransferFunctionBehavior fPremulBehavior;
scroggoeb602a52015-07-09 08:16:03 -0700308 };
309
310 /**
311 * Decode into the given pixels, a block of memory of size at
312 * least (info.fHeight - 1) * rowBytes + (info.fWidth *
313 * bytesPerPixel)
314 *
315 * Repeated calls to this function should give the same results,
316 * allowing the PixelRef to be immutable.
317 *
318 * @param info A description of the format (config, size)
319 * expected by the caller. This can simply be identical
320 * to the info returned by getInfo().
321 *
322 * This contract also allows the caller to specify
323 * different output-configs, which the implementation can
324 * decide to support or not.
325 *
326 * A size that does not match getInfo() implies a request
327 * to scale. If the generator cannot perform this scale,
328 * it will return kInvalidScale.
329 *
msarett50ce1f22016-07-29 06:23:33 -0700330 * If the info contains a non-null SkColorSpace, the codec
331 * will perform the appropriate color space transformation.
332 * If the caller passes in the same color space that was
333 * reported by the codec, the color space transformation is
334 * a no-op.
335 *
scroggo46c57472015-09-30 08:57:13 -0700336 * If a scanline decode is in progress, scanline mode will end, requiring the client to call
337 * startScanlineDecode() in order to return to decoding scanlines.
338 *
scroggoeb602a52015-07-09 08:16:03 -0700339 * @return Result kSuccess, or another value explaining the type of failure.
340 */
Leon Scroggins571b30f2017-07-11 17:35:31 +0000341 Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*);
scroggoeb602a52015-07-09 08:16:03 -0700342
343 /**
Leon Scroggins571b30f2017-07-11 17:35:31 +0000344 * Simplified version of getPixels() that uses the default Options.
scroggoeb602a52015-07-09 08:16:03 -0700345 */
Leon Scroggins571b30f2017-07-11 17:35:31 +0000346 Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
347 return this->getPixels(info, pixels, rowBytes, nullptr);
348 }
scroggoeb602a52015-07-09 08:16:03 -0700349
Mike Reed43798692017-10-17 18:04:32 +0000350 Result getPixels(const SkPixmap& pm, const Options* opts = nullptr) {
351 return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), opts);
352 }
353
msarettb714fb02016-01-22 14:46:42 -0800354 /**
355 * If decoding to YUV is supported, this returns true. Otherwise, this
356 * returns false and does not modify any of the parameters.
357 *
358 * @param sizeInfo Output parameter indicating the sizes and required
359 * allocation widths of the Y, U, and V planes.
360 * @param colorSpace Output parameter. If non-NULL this is set to kJPEG,
361 * otherwise this is ignored.
362 */
msarett4984c3c2016-03-10 05:44:43 -0800363 bool queryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
msarettb714fb02016-01-22 14:46:42 -0800364 if (nullptr == sizeInfo) {
365 return false;
366 }
367
368 return this->onQueryYUV8(sizeInfo, colorSpace);
369 }
370
371 /**
372 * Returns kSuccess, or another value explaining the type of failure.
373 * This always attempts to perform a full decode. If the client only
374 * wants size, it should call queryYUV8().
375 *
376 * @param sizeInfo Needs to exactly match the values returned by the
377 * query, except the WidthBytes may be larger than the
378 * recommendation (but not smaller).
379 * @param planes Memory for each of the Y, U, and V planes.
380 */
msarett4984c3c2016-03-10 05:44:43 -0800381 Result getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
msarettb714fb02016-01-22 14:46:42 -0800382 if (nullptr == planes || nullptr == planes[0] || nullptr == planes[1] ||
383 nullptr == planes[2]) {
384 return kInvalidInput;
385 }
386
387 if (!this->rewindIfNeeded()) {
388 return kCouldNotRewind;
389 }
390
391 return this->onGetYUV8Planes(sizeInfo, planes);
392 }
393
scroggoeb602a52015-07-09 08:16:03 -0700394 /**
scroggo8e6c7ad2016-09-16 08:20:38 -0700395 * Prepare for an incremental decode with the specified options.
396 *
397 * This may require a rewind.
398 *
399 * @param dstInfo Info of the destination. If the dimensions do not match
400 * those of getInfo, this implies a scale.
401 * @param dst Memory to write to. Needs to be large enough to hold the subset,
402 * if present, or the full image as described in dstInfo.
403 * @param options Contains decoding options, including if memory is zero
404 * initialized and whether to decode a subset.
scroggo8e6c7ad2016-09-16 08:20:38 -0700405 * @return Enum representing success or reason for failure.
406 */
407 Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
Leon Scroggins571b30f2017-07-11 17:35:31 +0000408 const Options*);
scroggo8e6c7ad2016-09-16 08:20:38 -0700409
410 Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes) {
Leon Scroggins571b30f2017-07-11 17:35:31 +0000411 return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr);
scroggo8e6c7ad2016-09-16 08:20:38 -0700412 }
413
414 /**
415 * Start/continue the incremental decode.
416 *
417 * Not valid to call before calling startIncrementalDecode().
418 *
419 * After the first call, should only be called again if more data has been
420 * provided to the source SkStream.
421 *
422 * Unlike getPixels and getScanlines, this does not do any filling. This is
423 * left up to the caller, since they may be skipping lines or continuing the
424 * decode later. In the latter case, they may choose to initialize all lines
425 * first, or only initialize the remaining lines after the first call.
426 *
427 * @param rowsDecoded Optional output variable returning the total number of
428 * lines initialized. Only meaningful if this method returns kIncompleteInput.
429 * Otherwise the implementation may not set it.
430 * Note that some implementations may have initialized this many rows, but
431 * not necessarily finished those rows (e.g. interlaced PNG). This may be
432 * useful for determining what rows the client needs to initialize.
433 * @return kSuccess if all lines requested in startIncrementalDecode have
434 * been completely decoded. kIncompleteInput otherwise.
435 */
436 Result incrementalDecode(int* rowsDecoded = nullptr) {
437 if (!fStartedIncrementalDecode) {
438 return kInvalidParameters;
439 }
440 return this->onIncrementalDecode(rowsDecoded);
441 }
442
443 /**
scroggo46c57472015-09-30 08:57:13 -0700444 * The remaining functions revolve around decoding scanlines.
445 */
446
447 /**
448 * Prepare for a scanline decode with the specified options.
449 *
450 * After this call, this class will be ready to decode the first scanline.
451 *
452 * This must be called in order to call getScanlines or skipScanlines.
453 *
454 * This may require rewinding the stream.
455 *
456 * Not all SkCodecs support this.
457 *
458 * @param dstInfo Info of the destination. If the dimensions do not match
459 * those of getInfo, this implies a scale.
460 * @param options Contains decoding options, including if memory is zero
461 * initialized.
scroggo46c57472015-09-30 08:57:13 -0700462 * @return Enum representing success or reason for failure.
463 */
Leon Scroggins571b30f2017-07-11 17:35:31 +0000464 Result startScanlineDecode(const SkImageInfo& dstInfo, const Options* options);
scroggo46c57472015-09-30 08:57:13 -0700465
466 /**
Leon Scroggins571b30f2017-07-11 17:35:31 +0000467 * Simplified version of startScanlineDecode() that uses the default Options.
scroggo46c57472015-09-30 08:57:13 -0700468 */
Leon Scroggins571b30f2017-07-11 17:35:31 +0000469 Result startScanlineDecode(const SkImageInfo& dstInfo) {
470 return this->startScanlineDecode(dstInfo, nullptr);
471 }
scroggo46c57472015-09-30 08:57:13 -0700472
473 /**
474 * Write the next countLines scanlines into dst.
475 *
476 * Not valid to call before calling startScanlineDecode().
477 *
478 * @param dst Must be non-null, and large enough to hold countLines
479 * scanlines of size rowBytes.
480 * @param countLines Number of lines to write.
481 * @param rowBytes Number of bytes per row. Must be large enough to hold
482 * a scanline based on the SkImageInfo used to create this object.
msarette6dd0042015-10-09 11:07:34 -0700483 * @return the number of lines successfully decoded. If this value is
484 * less than countLines, this will fill the remaining lines with a
485 * default value.
scroggo46c57472015-09-30 08:57:13 -0700486 */
msarette6dd0042015-10-09 11:07:34 -0700487 int getScanlines(void* dst, int countLines, size_t rowBytes);
scroggo46c57472015-09-30 08:57:13 -0700488
489 /**
490 * Skip count scanlines.
491 *
492 * Not valid to call before calling startScanlineDecode().
493 *
494 * The default version just calls onGetScanlines and discards the dst.
495 * NOTE: If skipped lines are the only lines with alpha, this default
496 * will make reallyHasAlpha return true, when it could have returned
497 * false.
msarette6dd0042015-10-09 11:07:34 -0700498 *
499 * @return true if the scanlines were successfully skipped
500 * false on failure, possible reasons for failure include:
501 * An incomplete input image stream.
502 * Calling this function before calling startScanlineDecode().
503 * If countLines is less than zero or so large that it moves
504 * the current scanline past the end of the image.
scroggo46c57472015-09-30 08:57:13 -0700505 */
msarette6dd0042015-10-09 11:07:34 -0700506 bool skipScanlines(int countLines);
scroggo46c57472015-09-30 08:57:13 -0700507
508 /**
509 * The order in which rows are output from the scanline decoder is not the
510 * same for all variations of all image types. This explains the possible
511 * output row orderings.
512 */
513 enum SkScanlineOrder {
514 /*
515 * By far the most common, this indicates that the image can be decoded
516 * reliably using the scanline decoder, and that rows will be output in
517 * the logical order.
518 */
519 kTopDown_SkScanlineOrder,
520
521 /*
522 * This indicates that the scanline decoder reliably outputs rows, but
523 * they will be returned in reverse order. If the scanline format is
524 * kBottomUp, the nextScanline() API can be used to determine the actual
525 * y-coordinate of the next output row, but the client is not forced
526 * to take advantage of this, given that it's not too tough to keep
527 * track independently.
528 *
529 * For full image decodes, it is safe to get all of the scanlines at
530 * once, since the decoder will handle inverting the rows as it
531 * decodes.
532 *
533 * For subset decodes and sampling, it is simplest to get and skip
534 * scanlines one at a time, using the nextScanline() API. It is
535 * possible to ask for larger chunks at a time, but this should be used
536 * with caution. As with full image decodes, the decoder will handle
537 * inverting the requested rows, but rows will still be delivered
538 * starting from the bottom of the image.
539 *
540 * Upside down bmps are an example.
541 */
542 kBottomUp_SkScanlineOrder,
scroggo46c57472015-09-30 08:57:13 -0700543 };
544
545 /**
546 * An enum representing the order in which scanlines will be returned by
547 * the scanline decoder.
msarettbe8216a2015-12-04 08:00:50 -0800548 *
549 * This is undefined before startScanlineDecode() is called.
scroggo46c57472015-09-30 08:57:13 -0700550 */
551 SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); }
552
553 /**
554 * Returns the y-coordinate of the next row to be returned by the scanline
msarette6dd0042015-10-09 11:07:34 -0700555 * decoder.
556 *
557 * This will equal fCurrScanline, except in the case of strangely
scroggo19b91532016-10-24 09:03:26 -0700558 * encoded image types (bottom-up bmps).
scroggo46c57472015-09-30 08:57:13 -0700559 *
560 * Results are undefined when not in scanline decoding mode.
561 */
msarette6dd0042015-10-09 11:07:34 -0700562 int nextScanline() const { return this->outputScanline(fCurrScanline); }
563
564 /**
msarettcb0d5c92015-12-03 12:23:43 -0800565 * Returns the output y-coordinate of the row that corresponds to an input
566 * y-coordinate. The input y-coordinate represents where the scanline
567 * is located in the encoded data.
msarette6dd0042015-10-09 11:07:34 -0700568 *
569 * This will equal inputScanline, except in the case of strangely
570 * encoded image types (bottom-up bmps, interlaced gifs).
571 */
572 int outputScanline(int inputScanline) const;
scroggo46c57472015-09-30 08:57:13 -0700573
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400574 /**
575 * Return the number of frames in the image.
576 *
577 * May require reading through the stream.
578 */
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400579 int getFrameCount() {
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400580 return this->onGetFrameCount();
581 }
582
scroggo19b91532016-10-24 09:03:26 -0700583 // The required frame for an independent frame is marked as
584 // kNone.
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400585 static constexpr int kNone = -1;
scroggo19b91532016-10-24 09:03:26 -0700586
587 /**
588 * Information about individual frames in a multi-framed image.
589 */
590 struct FrameInfo {
591 /**
592 * The frame that this frame needs to be blended with, or
Leon Scroggins III33deb7e2017-06-07 12:31:51 -0400593 * kNone if this frame is independent.
594 *
595 * Note that this is the *earliest* frame that can be used
596 * for blending. Any frame from [fRequiredFrame, i) can be
597 * used, unless its fDisposalMethod is kRestorePrevious.
scroggo19b91532016-10-24 09:03:26 -0700598 */
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400599 int fRequiredFrame;
scroggo19b91532016-10-24 09:03:26 -0700600
601 /**
602 * Number of milliseconds to show this frame.
603 */
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400604 int fDuration;
Leon Scroggins III3639faa2016-12-08 11:38:58 -0500605
606 /**
607 * Whether the end marker for this frame is contained in the stream.
608 *
609 * Note: this does not guarantee that an attempt to decode will be complete.
610 * There could be an error in the stream.
611 */
612 bool fFullyReceived;
Leon Scroggins IIIa4db9be2017-04-11 10:32:02 -0400613
614 /**
615 * This is conservative; it will still return non-opaque if e.g. a
616 * color index-based frame has a color with alpha but does not use it.
617 */
Leon Scroggins IIIc8037dc2017-12-05 13:55:24 -0500618 SkAlphaType fAlphaType;
Leon Scroggins III33deb7e2017-06-07 12:31:51 -0400619
620 /**
621 * How this frame should be modified before decoding the next one.
622 */
623 SkCodecAnimation::DisposalMethod fDisposalMethod;
scroggo19b91532016-10-24 09:03:26 -0700624 };
625
626 /**
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400627 * Return info about a single frame.
628 *
629 * Only supported by multi-frame images. Does not read through the stream,
630 * so it should be called after getFrameCount() to parse any frames that
631 * have not already been parsed.
632 */
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400633 bool getFrameInfo(int index, FrameInfo* info) const {
Leon Scroggins III557fbbe2017-05-23 09:37:21 -0400634 if (index < 0) {
635 return false;
636 }
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400637 return this->onGetFrameInfo(index, info);
638 }
639
640 /**
641 * Return info about all the frames in the image.
scroggo19b91532016-10-24 09:03:26 -0700642 *
scroggoe71b1a12016-11-01 08:28:28 -0700643 * May require reading through the stream to determine info about the
644 * frames (including the count).
scroggo19b91532016-10-24 09:03:26 -0700645 *
646 * As such, future decoding calls may require a rewind.
647 *
648 * For single-frame images, this will return an empty vector.
649 */
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400650 std::vector<FrameInfo> getFrameInfo();
scroggo19b91532016-10-24 09:03:26 -0700651
scroggoe71b1a12016-11-01 08:28:28 -0700652 static constexpr int kRepetitionCountInfinite = -1;
653
654 /**
655 * Return the number of times to repeat, if this image is animated.
656 *
657 * May require reading the stream to find the repetition count.
658 *
659 * As such, future decoding calls may require a rewind.
660 *
661 * For single-frame images, this will return 0.
662 */
663 int getRepetitionCount() {
664 return this->onGetRepetitionCount();
665 }
666
scroggof24f2242015-03-03 08:59:20 -0800667protected:
Leon Scroggins IIIc8037dc2017-12-05 13:55:24 -0500668 const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
669
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400670 using XformFormat = SkColorSpaceXform::ColorFormat;
671
msarettc30c4182016-04-20 11:53:35 -0700672 SkCodec(int width,
673 int height,
674 const SkEncodedInfo&,
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400675 XformFormat srcFormat,
Mike Reedede7bac2017-07-23 15:30:02 -0400676 std::unique_ptr<SkStream>,
Matt Sarett7f650bd2016-10-30 21:25:34 -0400677 sk_sp<SkColorSpace>,
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -0400678 SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
scroggof24f2242015-03-03 08:59:20 -0800679
msarett549ca322016-08-17 08:54:08 -0700680 /**
msarett549ca322016-08-17 08:54:08 -0700681 * Allows the subclass to set the recommended SkImageInfo
682 */
683 SkCodec(const SkEncodedInfo&,
684 const SkImageInfo&,
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400685 XformFormat srcFormat,
Mike Reedede7bac2017-07-23 15:30:02 -0400686 std::unique_ptr<SkStream>,
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -0400687 SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
msarett549ca322016-08-17 08:54:08 -0700688
msarettb714fb02016-01-22 14:46:42 -0800689 virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const {
scroggof24f2242015-03-03 08:59:20 -0800690 // By default, scaling is not supported.
halcanaryb880d7f2015-03-26 06:29:03 -0700691 return this->getInfo().dimensions();
scroggof24f2242015-03-03 08:59:20 -0800692 }
693
scroggoe7fc14b2015-10-02 13:14:46 -0700694 // FIXME: What to do about subsets??
695 /**
696 * Subclasses should override if they support dimensions other than the
697 * srcInfo's.
698 */
699 virtual bool onDimensionsSupported(const SkISize&) {
700 return false;
701 }
702
Hal Canarydb683012016-11-23 08:55:18 -0700703 virtual SkEncodedImageFormat onGetEncodedFormat() const = 0;
scroggo1dd3ea92015-03-20 11:55:55 -0700704
msarette6dd0042015-10-09 11:07:34 -0700705 /**
706 * @param rowsDecoded When the encoded image stream is incomplete, this function
707 * will return kIncompleteInput and rowsDecoded will be set to
708 * the number of scanlines that were successfully decoded.
709 * This will allow getPixels() to fill the uninitialized memory.
710 */
scroggoeb602a52015-07-09 08:16:03 -0700711 virtual Result onGetPixels(const SkImageInfo& info,
712 void* pixels, size_t rowBytes, const Options&,
msarette6dd0042015-10-09 11:07:34 -0700713 int* rowsDecoded) = 0;
scroggoeb602a52015-07-09 08:16:03 -0700714
msarett4984c3c2016-03-10 05:44:43 -0800715 virtual bool onQueryYUV8(SkYUVSizeInfo*, SkYUVColorSpace*) const {
msarettb714fb02016-01-22 14:46:42 -0800716 return false;
717 }
718
msarett4984c3c2016-03-10 05:44:43 -0800719 virtual Result onGetYUV8Planes(const SkYUVSizeInfo&, void*[3] /*planes*/) {
msarettb714fb02016-01-22 14:46:42 -0800720 return kUnimplemented;
721 }
722
723 virtual bool onGetValidSubset(SkIRect* /*desiredSubset*/) const {
scroggob636b452015-07-22 07:16:20 -0700724 // By default, subsets are not supported.
725 return false;
726 }
727
msarett90c4d5f2015-12-10 13:09:24 -0800728 /**
scroggof24f2242015-03-03 08:59:20 -0800729 * If the stream was previously read, attempt to rewind.
scroggob427db12015-08-12 07:24:13 -0700730 *
731 * If the stream needed to be rewound, call onRewind.
732 * @returns true if the codec is at the right position and can be used.
733 * false if there was a failure to rewind.
halcanarya096d7a2015-03-27 12:16:53 -0700734 *
scroggo3a7701c2015-09-30 09:15:14 -0700735 * This is called by getPixels() and start(). Subclasses may call if they
736 * need to rewind at another time.
scroggof24f2242015-03-03 08:59:20 -0800737 */
scroggob427db12015-08-12 07:24:13 -0700738 bool SK_WARN_UNUSED_RESULT rewindIfNeeded();
739
740 /**
741 * Called by rewindIfNeeded, if the stream needed to be rewound.
742 *
743 * Subclasses should do any set up needed after a rewind.
744 */
745 virtual bool onRewind() {
746 return true;
747 }
scroggof24f2242015-03-03 08:59:20 -0800748
msarettc0e80c12015-07-01 06:50:35 -0700749 /**
msarette6dd0042015-10-09 11:07:34 -0700750 * On an incomplete input, getPixels() and getScanlines() will fill any uninitialized
751 * scanlines. This allows the subclass to indicate what value to fill with.
752 *
msarettf7eb6fc2016-09-13 09:04:11 -0700753 * @param dstInfo Describes the destination.
msarette6dd0042015-10-09 11:07:34 -0700754 * @return The value with which to fill uninitialized pixels.
755 *
msarettf7eb6fc2016-09-13 09:04:11 -0700756 * Note that we can interpret the return value as a 64-bit Float16 color, a SkPMColor,
757 * a 16-bit 565 color, an 8-bit gray color, or an 8-bit index into a color table,
758 * depending on the color type.
msarette6dd0042015-10-09 11:07:34 -0700759 */
msarettf7eb6fc2016-09-13 09:04:11 -0700760 uint64_t getFillValue(const SkImageInfo& dstInfo) const {
761 return this->onGetFillValue(dstInfo);
msarette6dd0042015-10-09 11:07:34 -0700762 }
763
764 /**
765 * Some subclasses will override this function, but this is a useful default for the color
msarettf7eb6fc2016-09-13 09:04:11 -0700766 * types that we support. Note that for color types that do not use the full 64-bits,
msarette6dd0042015-10-09 11:07:34 -0700767 * we will simply take the low bits of the fill value.
768 *
msarettf7eb6fc2016-09-13 09:04:11 -0700769 * The defaults are:
770 * kRGBA_F16_SkColorType: Transparent or Black, depending on the src alpha type
scroggoc5560be2016-02-03 09:42:42 -0800771 * kN32_SkColorType: Transparent or Black, depending on the src alpha type
msarette6dd0042015-10-09 11:07:34 -0700772 * kRGB_565_SkColorType: Black
773 * kGray_8_SkColorType: Black
msarette6dd0042015-10-09 11:07:34 -0700774 */
msarettf7eb6fc2016-09-13 09:04:11 -0700775 virtual uint64_t onGetFillValue(const SkImageInfo& dstInfo) const;
msarette6dd0042015-10-09 11:07:34 -0700776
777 /**
msarett74114382015-03-16 11:55:18 -0700778 * Get method for the input stream
msarett74114382015-03-16 11:55:18 -0700779 */
780 SkStream* stream() {
781 return fStream.get();
782 }
783
scroggo46c57472015-09-30 08:57:13 -0700784 /**
785 * The remaining functions revolve around decoding scanlines.
786 */
787
788 /**
789 * Most images types will be kTopDown and will not need to override this function.
790 */
791 virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; }
792
scroggo46c57472015-09-30 08:57:13 -0700793 const SkImageInfo& dstInfo() const { return fDstInfo; }
794
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400795 const Options& options() const { return fOptions; }
scroggo46c57472015-09-30 08:57:13 -0700796
msarettcb0d5c92015-12-03 12:23:43 -0800797 /**
798 * Returns the number of scanlines that have been decoded so far.
799 * This is unaffected by the SkScanlineOrder.
800 *
801 * Returns -1 if we have not started a scanline decode.
802 */
803 int currScanline() const { return fCurrScanline; }
804
msarette6dd0042015-10-09 11:07:34 -0700805 virtual int onOutputScanline(int inputScanline) const;
806
Leon Scroggins IIIae79f322017-08-18 10:53:24 -0400807 bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha,
Matt Sarettcf3f2342017-03-23 15:32:25 -0400808 SkTransferFunctionBehavior premulBehavior);
Leon Scroggins IIIae79f322017-08-18 10:53:24 -0400809 // Some classes never need a colorXform e.g.
810 // - ICO uses its embedded codec's colorXform
811 // - WBMP is just Black/White
812 virtual bool usesColorXform() const { return true; }
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400813 void applyColorXform(void* dst, const void* src, int count, SkAlphaType) const;
814 void applyColorXform(void* dst, const void* src, int count) const;
815
Matt Sarett313c4632016-10-20 12:35:23 -0400816 SkColorSpaceXform* colorXform() const { return fColorXform.get(); }
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400817 bool xformOnDecode() const { return fXformOnDecode; }
Matt Sarett313c4632016-10-20 12:35:23 -0400818
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400819 virtual int onGetFrameCount() {
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400820 return 1;
821 }
822
Leon Scroggins III249b8e32017-04-17 12:46:33 -0400823 virtual bool onGetFrameInfo(int, FrameInfo*) const {
Leon Scroggins IIIe132e7b2017-04-12 10:49:52 -0400824 return false;
scroggo19b91532016-10-24 09:03:26 -0700825 }
826
scroggoe71b1a12016-11-01 08:28:28 -0700827 virtual int onGetRepetitionCount() {
828 return 0;
829 }
830
Matt Sarett313c4632016-10-20 12:35:23 -0400831private:
832 const SkEncodedInfo fEncodedInfo;
833 const SkImageInfo fSrcInfo;
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400834 const XformFormat fSrcXformFormat;
bungeman6bd52842016-10-27 09:30:08 -0700835 std::unique_ptr<SkStream> fStream;
Matt Sarett313c4632016-10-20 12:35:23 -0400836 bool fNeedsRewind;
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -0400837 const SkEncodedOrigin fOrigin;
Matt Sarett313c4632016-10-20 12:35:23 -0400838
839 SkImageInfo fDstInfo;
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400840 Options fOptions;
841 XformFormat fDstXformFormat; // Based on fDstInfo.
Matt Sarett313c4632016-10-20 12:35:23 -0400842 std::unique_ptr<SkColorSpaceXform> fColorXform;
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400843 bool fXformOnDecode;
scroggo8e6c7ad2016-09-16 08:20:38 -0700844
845 // Only meaningful during scanline decodes.
Matt Sarett313c4632016-10-20 12:35:23 -0400846 int fCurrScanline;
scroggo46c57472015-09-30 08:57:13 -0700847
Matt Sarett313c4632016-10-20 12:35:23 -0400848 bool fStartedIncrementalDecode;
scroggo8e6c7ad2016-09-16 08:20:38 -0700849
scroggoe7fc14b2015-10-02 13:14:46 -0700850 /**
Leon Scroggins III07418182017-08-15 12:24:02 -0400851 * Return whether {srcColor, srcIsOpaque, srcCS} can convert to dst.
852 *
853 * Will be called for the appropriate frame, prior to initializing the colorXform.
854 */
Leon Scroggins IIIc8037dc2017-12-05 13:55:24 -0500855 virtual bool conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
Leon Scroggins III07418182017-08-15 12:24:02 -0400856 bool srcIsOpaque, const SkColorSpace* srcCS) const;
857 /**
scroggoe7fc14b2015-10-02 13:14:46 -0700858 * Return whether these dimensions are supported as a scale.
859 *
860 * The codec may choose to cache the information about scale and subset.
861 * Either way, the same information will be passed to onGetPixels/onStart
862 * on success.
863 *
864 * This must return true for a size returned from getScaledDimensions.
865 */
866 bool dimensionsSupported(const SkISize& dim) {
867 return dim == fSrcInfo.dimensions() || this->onDimensionsSupported(dim);
868 }
869
Leon Scroggins III1f6af6b2017-06-12 16:41:09 -0400870 /**
871 * For multi-framed images, return the object with information about the frames.
872 */
873 virtual const SkFrameHolder* getFrameHolder() const {
874 return nullptr;
875 }
876
877 /**
878 * Check for a valid Options.fFrameIndex, and decode prior frames if necessary.
879 */
880 Result handleFrameIndex(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&);
881
scroggo46c57472015-09-30 08:57:13 -0700882 // Methods for scanline decoding.
Leon Scroggins IIIc6e6a5f2017-06-05 15:53:38 -0400883 virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/,
Leon Scroggins571b30f2017-07-11 17:35:31 +0000884 const Options& /*options*/) {
scroggo46c57472015-09-30 08:57:13 -0700885 return kUnimplemented;
886 }
887
scroggo8e6c7ad2016-09-16 08:20:38 -0700888 virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t,
Leon Scroggins571b30f2017-07-11 17:35:31 +0000889 const Options&) {
scroggo8e6c7ad2016-09-16 08:20:38 -0700890 return kUnimplemented;
891 }
892
893 virtual Result onIncrementalDecode(int*) {
894 return kUnimplemented;
895 }
896
897
msarett9b9497e2016-02-11 13:29:36 -0800898 virtual bool onSkipScanlines(int /*countLines*/) { return false; }
scroggo46c57472015-09-30 08:57:13 -0700899
msarett33bee092015-11-11 12:43:07 -0800900 virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; }
msarette6dd0042015-10-09 11:07:34 -0700901
902 /**
903 * On an incomplete decode, getPixels() and getScanlines() will call this function
904 * to fill any uinitialized memory.
905 *
906 * @param dstInfo Contains the destination color type
907 * Contains the destination alpha type
908 * Contains the destination width
909 * The height stored in this info is unused
910 * @param dst Pointer to the start of destination pixel memory
911 * @param rowBytes Stride length in destination pixel memory
912 * @param zeroInit Indicates if memory is zero initialized
913 * @param linesRequested Number of lines that the client requested
914 * @param linesDecoded Number of lines that were successfully decoded
915 */
916 void fillIncompleteImage(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
917 ZeroInitialized zeroInit, int linesRequested, int linesDecoded);
scroggo46c57472015-09-30 08:57:13 -0700918
scroggoe7fc14b2015-10-02 13:14:46 -0700919 /**
920 * Return an object which will allow forcing scanline decodes to sample in X.
921 *
922 * May create a sampler, if one is not currently being used. Otherwise, does
923 * not affect ownership.
924 *
scroggo19b91532016-10-24 09:03:26 -0700925 * Only valid during scanline decoding or incremental decoding.
scroggoe7fc14b2015-10-02 13:14:46 -0700926 */
msarett33bee092015-11-11 12:43:07 -0800927 virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; }
scroggoe7fc14b2015-10-02 13:14:46 -0700928
scroggo8e6c7ad2016-09-16 08:20:38 -0700929 friend class DM::CodecSrc; // for fillIncompleteImage
msarett3d9d7a72015-10-21 10:27:10 -0700930 friend class SkSampledCodec;
msarettbe8216a2015-12-04 08:00:50 -0800931 friend class SkIcoCodec;
Leon Scroggins IIIc8037dc2017-12-05 13:55:24 -0500932 friend class SkAndroidCodec; // for fEncodedInfo
scroggof24f2242015-03-03 08:59:20 -0800933};
934#endif // SkCodec_DEFINED