| 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 SkCodec_DEFINED | 
|---|
| 9 | #define SkCodec_DEFINED | 
|---|
| 10 |  | 
|---|
| 11 | #include "include/codec/SkCodecAnimation.h" | 
|---|
| 12 | #include "include/codec/SkEncodedOrigin.h" | 
|---|
| 13 | #include "include/core/SkColor.h" | 
|---|
| 14 | #include "include/core/SkEncodedImageFormat.h" | 
|---|
| 15 | #include "include/core/SkImageInfo.h" | 
|---|
| 16 | #include "include/core/SkPixmap.h" | 
|---|
| 17 | #include "include/core/SkSize.h" | 
|---|
| 18 | #include "include/core/SkStream.h" | 
|---|
| 19 | #include "include/core/SkTypes.h" | 
|---|
| 20 | #include "include/core/SkYUVASizeInfo.h" | 
|---|
| 21 | #include "include/private/SkEncodedInfo.h" | 
|---|
| 22 | #include "include/private/SkNoncopyable.h" | 
|---|
| 23 | #include "include/private/SkTemplates.h" | 
|---|
| 24 |  | 
|---|
| 25 | #include <vector> | 
|---|
| 26 |  | 
|---|
| 27 | class SkColorSpace; | 
|---|
| 28 | class SkData; | 
|---|
| 29 | class SkFrameHolder; | 
|---|
| 30 | class SkPngChunkReader; | 
|---|
| 31 | class SkSampler; | 
|---|
| 32 |  | 
|---|
| 33 | namespace DM { | 
|---|
| 34 | class CodecSrc; | 
|---|
| 35 | class ColorCodecSrc; | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | /** | 
|---|
| 39 | *  Abstraction layer directly on top of an image codec. | 
|---|
| 40 | */ | 
|---|
| 41 | class SK_API SkCodec : SkNoncopyable { | 
|---|
| 42 | public: | 
|---|
| 43 | /** | 
|---|
| 44 | *  Minimum number of bytes that must be buffered in SkStream input. | 
|---|
| 45 | * | 
|---|
| 46 | *  An SkStream passed to NewFromStream must be able to use this many | 
|---|
| 47 | *  bytes to determine the image type. Then the same SkStream must be | 
|---|
| 48 | *  passed to the correct decoder to read from the beginning. | 
|---|
| 49 | * | 
|---|
| 50 | *  This can be accomplished by implementing peek() to support peeking | 
|---|
| 51 | *  this many bytes, or by implementing rewind() to be able to rewind() | 
|---|
| 52 | *  after reading this many bytes. | 
|---|
| 53 | */ | 
|---|
| 54 | static constexpr size_t MinBufferedBytesNeeded() { return 32; } | 
|---|
| 55 |  | 
|---|
| 56 | /** | 
|---|
| 57 | *  Error codes for various SkCodec methods. | 
|---|
| 58 | */ | 
|---|
| 59 | enum Result { | 
|---|
| 60 | /** | 
|---|
| 61 | *  General return value for success. | 
|---|
| 62 | */ | 
|---|
| 63 | kSuccess, | 
|---|
| 64 | /** | 
|---|
| 65 | *  The input is incomplete. A partial image was generated. | 
|---|
| 66 | */ | 
|---|
| 67 | kIncompleteInput, | 
|---|
| 68 | /** | 
|---|
| 69 | *  Like kIncompleteInput, except the input had an error. | 
|---|
| 70 | * | 
|---|
| 71 | *  If returned from an incremental decode, decoding cannot continue, | 
|---|
| 72 | *  even with more data. | 
|---|
| 73 | */ | 
|---|
| 74 | kErrorInInput, | 
|---|
| 75 | /** | 
|---|
| 76 | *  The generator cannot convert to match the request, ignoring | 
|---|
| 77 | *  dimensions. | 
|---|
| 78 | */ | 
|---|
| 79 | kInvalidConversion, | 
|---|
| 80 | /** | 
|---|
| 81 | *  The generator cannot scale to requested size. | 
|---|
| 82 | */ | 
|---|
| 83 | kInvalidScale, | 
|---|
| 84 | /** | 
|---|
| 85 | *  Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes | 
|---|
| 86 | *  too small, etc. | 
|---|
| 87 | */ | 
|---|
| 88 | kInvalidParameters, | 
|---|
| 89 | /** | 
|---|
| 90 | *  The input did not contain a valid image. | 
|---|
| 91 | */ | 
|---|
| 92 | kInvalidInput, | 
|---|
| 93 | /** | 
|---|
| 94 | *  Fulfilling this request requires rewinding the input, which is not | 
|---|
| 95 | *  supported for this input. | 
|---|
| 96 | */ | 
|---|
| 97 | kCouldNotRewind, | 
|---|
| 98 | /** | 
|---|
| 99 | *  An internal error, such as OOM. | 
|---|
| 100 | */ | 
|---|
| 101 | kInternalError, | 
|---|
| 102 | /** | 
|---|
| 103 | *  This method is not implemented by this codec. | 
|---|
| 104 | *  FIXME: Perhaps this should be kUnsupported? | 
|---|
| 105 | */ | 
|---|
| 106 | kUnimplemented, | 
|---|
| 107 | }; | 
|---|
| 108 |  | 
|---|
| 109 | /** | 
|---|
| 110 | *  Readable string representing the error code. | 
|---|
| 111 | */ | 
|---|
| 112 | static const char* ResultToString(Result); | 
|---|
| 113 |  | 
|---|
| 114 | /** | 
|---|
| 115 | * For container formats that contain both still images and image sequences, | 
|---|
| 116 | * instruct the decoder how the output should be selected. (Refer to comments | 
|---|
| 117 | * for each value for more details.) | 
|---|
| 118 | */ | 
|---|
| 119 | enum class SelectionPolicy { | 
|---|
| 120 | /** | 
|---|
| 121 | *  If the container format contains both still images and image sequences, | 
|---|
| 122 | *  SkCodec should choose one of the still images. This is the default. | 
|---|
| 123 | */ | 
|---|
| 124 | kPreferStillImage, | 
|---|
| 125 | /** | 
|---|
| 126 | *  If the container format contains both still images and image sequences, | 
|---|
| 127 | *  SkCodec should choose one of the image sequences for animation. | 
|---|
| 128 | */ | 
|---|
| 129 | kPreferAnimation, | 
|---|
| 130 | }; | 
|---|
| 131 |  | 
|---|
| 132 | /** | 
|---|
| 133 | *  If this stream represents an encoded image that we know how to decode, | 
|---|
| 134 | *  return an SkCodec that can decode it. Otherwise return NULL. | 
|---|
| 135 | * | 
|---|
| 136 | *  As stated above, this call must be able to peek or read | 
|---|
| 137 | *  MinBufferedBytesNeeded to determine the correct format, and then start | 
|---|
| 138 | *  reading from the beginning. First it will attempt to peek, and it | 
|---|
| 139 | *  assumes that if less than MinBufferedBytesNeeded bytes (but more than | 
|---|
| 140 | *  zero) are returned, this is because the stream is shorter than this, | 
|---|
| 141 | *  so falling back to reading would not provide more data. If peek() | 
|---|
| 142 | *  returns zero bytes, this call will instead attempt to read(). This | 
|---|
| 143 | *  will require that the stream can be rewind()ed. | 
|---|
| 144 | * | 
|---|
| 145 | *  If Result is not NULL, it will be set to either kSuccess if an SkCodec | 
|---|
| 146 | *  is returned or a reason for the failure if NULL is returned. | 
|---|
| 147 | * | 
|---|
| 148 | *  If SkPngChunkReader is not NULL, take a ref and pass it to libpng if | 
|---|
| 149 | *  the image is a png. | 
|---|
| 150 | * | 
|---|
| 151 | *  If the SkPngChunkReader is not NULL then: | 
|---|
| 152 | *      If the image is not a PNG, the SkPngChunkReader will be ignored. | 
|---|
| 153 | *      If the image is a PNG, the SkPngChunkReader will be reffed. | 
|---|
| 154 | *      If the PNG has unknown chunks, the SkPngChunkReader will be used | 
|---|
| 155 | *      to handle these chunks.  SkPngChunkReader will be called to read | 
|---|
| 156 | *      any unknown chunk at any point during the creation of the codec | 
|---|
| 157 | *      or the decode.  Note that if SkPngChunkReader fails to read a | 
|---|
| 158 | *      chunk, this could result in a failure to create the codec or a | 
|---|
| 159 | *      failure to decode the image. | 
|---|
| 160 | *      If the PNG does not contain unknown chunks, the SkPngChunkReader | 
|---|
| 161 | *      will not be used or modified. | 
|---|
| 162 | * | 
|---|
| 163 | *  If NULL is returned, the stream is deleted immediately. Otherwise, the | 
|---|
| 164 | *  SkCodec takes ownership of it, and will delete it when done with it. | 
|---|
| 165 | */ | 
|---|
| 166 | static std::unique_ptr<SkCodec> MakeFromStream( | 
|---|
| 167 | std::unique_ptr<SkStream>, Result* = nullptr, | 
|---|
| 168 | SkPngChunkReader* = nullptr, | 
|---|
| 169 | SelectionPolicy selectionPolicy = SelectionPolicy::kPreferStillImage); | 
|---|
| 170 |  | 
|---|
| 171 | /** | 
|---|
| 172 | *  If this data represents an encoded image that we know how to decode, | 
|---|
| 173 | *  return an SkCodec that can decode it. Otherwise return NULL. | 
|---|
| 174 | * | 
|---|
| 175 | *  If the SkPngChunkReader is not NULL then: | 
|---|
| 176 | *      If the image is not a PNG, the SkPngChunkReader will be ignored. | 
|---|
| 177 | *      If the image is a PNG, the SkPngChunkReader will be reffed. | 
|---|
| 178 | *      If the PNG has unknown chunks, the SkPngChunkReader will be used | 
|---|
| 179 | *      to handle these chunks.  SkPngChunkReader will be called to read | 
|---|
| 180 | *      any unknown chunk at any point during the creation of the codec | 
|---|
| 181 | *      or the decode.  Note that if SkPngChunkReader fails to read a | 
|---|
| 182 | *      chunk, this could result in a failure to create the codec or a | 
|---|
| 183 | *      failure to decode the image. | 
|---|
| 184 | *      If the PNG does not contain unknown chunks, the SkPngChunkReader | 
|---|
| 185 | *      will not be used or modified. | 
|---|
| 186 | */ | 
|---|
| 187 | static std::unique_ptr<SkCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr); | 
|---|
| 188 |  | 
|---|
| 189 | virtual ~SkCodec(); | 
|---|
| 190 |  | 
|---|
| 191 | /** | 
|---|
| 192 | *  Return a reasonable SkImageInfo to decode into. | 
|---|
| 193 | * | 
|---|
| 194 | *  If the image has an ICC profile that does not map to an SkColorSpace, | 
|---|
| 195 | *  the returned SkImageInfo will use SRGB. | 
|---|
| 196 | */ | 
|---|
| 197 | SkImageInfo getInfo() const { return fEncodedInfo.makeImageInfo(); } | 
|---|
| 198 |  | 
|---|
| 199 | SkISize dimensions() const { return {fEncodedInfo.width(), fEncodedInfo.height()}; } | 
|---|
| 200 | SkIRect bounds() const { | 
|---|
| 201 | return SkIRect::MakeWH(fEncodedInfo.width(), fEncodedInfo.height()); | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | /** | 
|---|
| 205 | * Return the ICC profile of the encoded data. | 
|---|
| 206 | */ | 
|---|
| 207 | const skcms_ICCProfile* getICCProfile() const { | 
|---|
| 208 | return this->getEncodedInfo().profile(); | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 | /** | 
|---|
| 212 | *  Returns the image orientation stored in the EXIF data. | 
|---|
| 213 | *  If there is no EXIF data, or if we cannot read the EXIF data, returns kTopLeft. | 
|---|
| 214 | */ | 
|---|
| 215 | SkEncodedOrigin getOrigin() const { return fOrigin; } | 
|---|
| 216 |  | 
|---|
| 217 | /** | 
|---|
| 218 | *  Return a size that approximately supports the desired scale factor. | 
|---|
| 219 | *  The codec may not be able to scale efficiently to the exact scale | 
|---|
| 220 | *  factor requested, so return a size that approximates that scale. | 
|---|
| 221 | *  The returned value is the codec's suggestion for the closest valid | 
|---|
| 222 | *  scale that it can natively support | 
|---|
| 223 | */ | 
|---|
| 224 | SkISize getScaledDimensions(float desiredScale) const { | 
|---|
| 225 | // Negative and zero scales are errors. | 
|---|
| 226 | SkASSERT(desiredScale > 0.0f); | 
|---|
| 227 | if (desiredScale <= 0.0f) { | 
|---|
| 228 | return SkISize::Make(0, 0); | 
|---|
| 229 | } | 
|---|
| 230 |  | 
|---|
| 231 | // Upscaling is not supported. Return the original size if the client | 
|---|
| 232 | // requests an upscale. | 
|---|
| 233 | if (desiredScale >= 1.0f) { | 
|---|
| 234 | return this->dimensions(); | 
|---|
| 235 | } | 
|---|
| 236 | return this->onGetScaledDimensions(desiredScale); | 
|---|
| 237 | } | 
|---|
| 238 |  | 
|---|
| 239 | /** | 
|---|
| 240 | *  Return (via desiredSubset) a subset which can decoded from this codec, | 
|---|
| 241 | *  or false if this codec cannot decode subsets or anything similar to | 
|---|
| 242 | *  desiredSubset. | 
|---|
| 243 | * | 
|---|
| 244 | *  @param desiredSubset In/out parameter. As input, a desired subset of | 
|---|
| 245 | *      the original bounds (as specified by getInfo). If true is returned, | 
|---|
| 246 | *      desiredSubset may have been modified to a subset which is | 
|---|
| 247 | *      supported. Although a particular change may have been made to | 
|---|
| 248 | *      desiredSubset to create something supported, it is possible other | 
|---|
| 249 | *      changes could result in a valid subset. | 
|---|
| 250 | *      If false is returned, desiredSubset's value is undefined. | 
|---|
| 251 | *  @return true if this codec supports decoding desiredSubset (as | 
|---|
| 252 | *      returned, potentially modified) | 
|---|
| 253 | */ | 
|---|
| 254 | bool getValidSubset(SkIRect* desiredSubset) const { | 
|---|
| 255 | return this->onGetValidSubset(desiredSubset); | 
|---|
| 256 | } | 
|---|
| 257 |  | 
|---|
| 258 | /** | 
|---|
| 259 | *  Format of the encoded data. | 
|---|
| 260 | */ | 
|---|
| 261 | SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); } | 
|---|
| 262 |  | 
|---|
| 263 | /** | 
|---|
| 264 | *  Whether or not the memory passed to getPixels is zero initialized. | 
|---|
| 265 | */ | 
|---|
| 266 | enum ZeroInitialized { | 
|---|
| 267 | /** | 
|---|
| 268 | *  The memory passed to getPixels is zero initialized. The SkCodec | 
|---|
| 269 | *  may take advantage of this by skipping writing zeroes. | 
|---|
| 270 | */ | 
|---|
| 271 | kYes_ZeroInitialized, | 
|---|
| 272 | /** | 
|---|
| 273 | *  The memory passed to getPixels has not been initialized to zero, | 
|---|
| 274 | *  so the SkCodec must write all zeroes to memory. | 
|---|
| 275 | * | 
|---|
| 276 | *  This is the default. It will be used if no Options struct is used. | 
|---|
| 277 | */ | 
|---|
| 278 | kNo_ZeroInitialized, | 
|---|
| 279 | }; | 
|---|
| 280 |  | 
|---|
| 281 | /** | 
|---|
| 282 | *  Additional options to pass to getPixels. | 
|---|
| 283 | */ | 
|---|
| 284 | struct Options { | 
|---|
| 285 | Options() | 
|---|
| 286 | : fZeroInitialized(kNo_ZeroInitialized) | 
|---|
| 287 | , fSubset(nullptr) | 
|---|
| 288 | , fFrameIndex(0) | 
|---|
| 289 | , fPriorFrame(kNoFrame) | 
|---|
| 290 | {} | 
|---|
| 291 |  | 
|---|
| 292 | ZeroInitialized            fZeroInitialized; | 
|---|
| 293 | /** | 
|---|
| 294 | *  If not NULL, represents a subset of the original image to decode. | 
|---|
| 295 | *  Must be within the bounds returned by getInfo(). | 
|---|
| 296 | *  If the EncodedFormat is SkEncodedImageFormat::kWEBP (the only one which | 
|---|
| 297 | *  currently supports subsets), the top and left values must be even. | 
|---|
| 298 | * | 
|---|
| 299 | *  In getPixels and incremental decode, we will attempt to decode the | 
|---|
| 300 | *  exact rectangular subset specified by fSubset. | 
|---|
| 301 | * | 
|---|
| 302 | *  In a scanline decode, it does not make sense to specify a subset | 
|---|
| 303 | *  top or subset height, since the client already controls which rows | 
|---|
| 304 | *  to get and which rows to skip.  During scanline decodes, we will | 
|---|
| 305 | *  require that the subset top be zero and the subset height be equal | 
|---|
| 306 | *  to the full height.  We will, however, use the values of | 
|---|
| 307 | *  subset left and subset width to decode partial scanlines on calls | 
|---|
| 308 | *  to getScanlines(). | 
|---|
| 309 | */ | 
|---|
| 310 | const SkIRect*             fSubset; | 
|---|
| 311 |  | 
|---|
| 312 | /** | 
|---|
| 313 | *  The frame to decode. | 
|---|
| 314 | * | 
|---|
| 315 | *  Only meaningful for multi-frame images. | 
|---|
| 316 | */ | 
|---|
| 317 | int                        fFrameIndex; | 
|---|
| 318 |  | 
|---|
| 319 | /** | 
|---|
| 320 | *  If not kNoFrame, the dst already contains the prior frame at this index. | 
|---|
| 321 | * | 
|---|
| 322 | *  Only meaningful for multi-frame images. | 
|---|
| 323 | * | 
|---|
| 324 | *  If fFrameIndex needs to be blended with a prior frame (as reported by | 
|---|
| 325 | *  getFrameInfo[fFrameIndex].fRequiredFrame), the client can set this to | 
|---|
| 326 | *  any non-kRestorePrevious frame in [fRequiredFrame, fFrameIndex) to | 
|---|
| 327 | *  indicate that that frame is already in the dst. Options.fZeroInitialized | 
|---|
| 328 | *  is ignored in this case. | 
|---|
| 329 | * | 
|---|
| 330 | *  If set to kNoFrame, the codec will decode any necessary required frame(s) first. | 
|---|
| 331 | */ | 
|---|
| 332 | int                        fPriorFrame; | 
|---|
| 333 | }; | 
|---|
| 334 |  | 
|---|
| 335 | /** | 
|---|
| 336 | *  Decode into the given pixels, a block of memory of size at | 
|---|
| 337 | *  least (info.fHeight - 1) * rowBytes + (info.fWidth * | 
|---|
| 338 | *  bytesPerPixel) | 
|---|
| 339 | * | 
|---|
| 340 | *  Repeated calls to this function should give the same results, | 
|---|
| 341 | *  allowing the PixelRef to be immutable. | 
|---|
| 342 | * | 
|---|
| 343 | *  @param info A description of the format (config, size) | 
|---|
| 344 | *         expected by the caller.  This can simply be identical | 
|---|
| 345 | *         to the info returned by getInfo(). | 
|---|
| 346 | * | 
|---|
| 347 | *         This contract also allows the caller to specify | 
|---|
| 348 | *         different output-configs, which the implementation can | 
|---|
| 349 | *         decide to support or not. | 
|---|
| 350 | * | 
|---|
| 351 | *         A size that does not match getInfo() implies a request | 
|---|
| 352 | *         to scale. If the generator cannot perform this scale, | 
|---|
| 353 | *         it will return kInvalidScale. | 
|---|
| 354 | * | 
|---|
| 355 | *         If the info contains a non-null SkColorSpace, the codec | 
|---|
| 356 | *         will perform the appropriate color space transformation. | 
|---|
| 357 | * | 
|---|
| 358 | *         If the caller passes in the SkColorSpace that maps to the | 
|---|
| 359 | *         ICC profile reported by getICCProfile(), the color space | 
|---|
| 360 | *         transformation is a no-op. | 
|---|
| 361 | * | 
|---|
| 362 | *         If the caller passes a null SkColorSpace, no color space | 
|---|
| 363 | *         transformation will be done. | 
|---|
| 364 | * | 
|---|
| 365 | *  If a scanline decode is in progress, scanline mode will end, requiring the client to call | 
|---|
| 366 | *  startScanlineDecode() in order to return to decoding scanlines. | 
|---|
| 367 | * | 
|---|
| 368 | *  @return Result kSuccess, or another value explaining the type of failure. | 
|---|
| 369 | */ | 
|---|
| 370 | Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*); | 
|---|
| 371 |  | 
|---|
| 372 | /** | 
|---|
| 373 | *  Simplified version of getPixels() that uses the default Options. | 
|---|
| 374 | */ | 
|---|
| 375 | Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { | 
|---|
| 376 | return this->getPixels(info, pixels, rowBytes, nullptr); | 
|---|
| 377 | } | 
|---|
| 378 |  | 
|---|
| 379 | Result getPixels(const SkPixmap& pm, const Options* opts = nullptr) { | 
|---|
| 380 | return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), opts); | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | /** | 
|---|
| 384 | *  If decoding to YUV is supported, this returns true.  Otherwise, this | 
|---|
| 385 | *  returns false and does not modify any of the parameters. | 
|---|
| 386 | * | 
|---|
| 387 | *  @param sizeInfo   Output parameter indicating the sizes and required | 
|---|
| 388 | *                    allocation widths of the Y, U, V, and A planes. Given current codec | 
|---|
| 389 | *                    limitations the size of the A plane will always be 0 and the Y, U, V | 
|---|
| 390 | *                    channels will always be planar. | 
|---|
| 391 | *  @param colorSpace Output parameter.  If non-NULL this is set to kJPEG, | 
|---|
| 392 | *                    otherwise this is ignored. | 
|---|
| 393 | */ | 
|---|
| 394 | bool queryYUV8(SkYUVASizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const { | 
|---|
| 395 | if (nullptr == sizeInfo) { | 
|---|
| 396 | return false; | 
|---|
| 397 | } | 
|---|
| 398 |  | 
|---|
| 399 | bool result = this->onQueryYUV8(sizeInfo, colorSpace); | 
|---|
| 400 | if (result) { | 
|---|
| 401 | for (int i = 0; i <= 2; ++i) { | 
|---|
| 402 | SkASSERT(sizeInfo->fSizes[i].fWidth > 0 && sizeInfo->fSizes[i].fHeight > 0 && | 
|---|
| 403 | sizeInfo->fWidthBytes[i] > 0); | 
|---|
| 404 | } | 
|---|
| 405 | SkASSERT(!sizeInfo->fSizes[3].fWidth && | 
|---|
| 406 | !sizeInfo->fSizes[3].fHeight && | 
|---|
| 407 | !sizeInfo->fWidthBytes[3]); | 
|---|
| 408 | } | 
|---|
| 409 | return result; | 
|---|
| 410 | } | 
|---|
| 411 |  | 
|---|
| 412 | /** | 
|---|
| 413 | *  Returns kSuccess, or another value explaining the type of failure. | 
|---|
| 414 | *  This always attempts to perform a full decode.  If the client only | 
|---|
| 415 | *  wants size, it should call queryYUV8(). | 
|---|
| 416 | * | 
|---|
| 417 | *  @param sizeInfo   Needs to exactly match the values returned by the | 
|---|
| 418 | *                    query, except the WidthBytes may be larger than the | 
|---|
| 419 | *                    recommendation (but not smaller). | 
|---|
| 420 | *  @param planes     Memory for each of the Y, U, and V planes. | 
|---|
| 421 | */ | 
|---|
| 422 | Result getYUV8Planes(const SkYUVASizeInfo& sizeInfo, void* planes[SkYUVASizeInfo::kMaxCount]) { | 
|---|
| 423 | if (!planes || !planes[0] || !planes[1] || !planes[2]) { | 
|---|
| 424 | return kInvalidInput; | 
|---|
| 425 | } | 
|---|
| 426 | SkASSERT(!planes[3]); // TODO: is this a fair assumption? | 
|---|
| 427 |  | 
|---|
| 428 | if (!this->rewindIfNeeded()) { | 
|---|
| 429 | return kCouldNotRewind; | 
|---|
| 430 | } | 
|---|
| 431 |  | 
|---|
| 432 | return this->onGetYUV8Planes(sizeInfo, planes); | 
|---|
| 433 | } | 
|---|
| 434 |  | 
|---|
| 435 | /** | 
|---|
| 436 | *  Prepare for an incremental decode with the specified options. | 
|---|
| 437 | * | 
|---|
| 438 | *  This may require a rewind. | 
|---|
| 439 | * | 
|---|
| 440 | *  If kIncompleteInput is returned, may be called again after more data has | 
|---|
| 441 | *  been provided to the source SkStream. | 
|---|
| 442 | * | 
|---|
| 443 | *  @param dstInfo Info of the destination. If the dimensions do not match | 
|---|
| 444 | *      those of getInfo, this implies a scale. | 
|---|
| 445 | *  @param dst Memory to write to. Needs to be large enough to hold the subset, | 
|---|
| 446 | *      if present, or the full image as described in dstInfo. | 
|---|
| 447 | *  @param options Contains decoding options, including if memory is zero | 
|---|
| 448 | *      initialized and whether to decode a subset. | 
|---|
| 449 | *  @return Enum representing success or reason for failure. | 
|---|
| 450 | */ | 
|---|
| 451 | Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, | 
|---|
| 452 | const Options*); | 
|---|
| 453 |  | 
|---|
| 454 | Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes) { | 
|---|
| 455 | return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr); | 
|---|
| 456 | } | 
|---|
| 457 |  | 
|---|
| 458 | /** | 
|---|
| 459 | *  Start/continue the incremental decode. | 
|---|
| 460 | * | 
|---|
| 461 | *  Not valid to call before a call to startIncrementalDecode() returns | 
|---|
| 462 | *  kSuccess. | 
|---|
| 463 | * | 
|---|
| 464 | *  If kIncompleteInput is returned, may be called again after more data has | 
|---|
| 465 | *  been provided to the source SkStream. | 
|---|
| 466 | * | 
|---|
| 467 | *  Unlike getPixels and getScanlines, this does not do any filling. This is | 
|---|
| 468 | *  left up to the caller, since they may be skipping lines or continuing the | 
|---|
| 469 | *  decode later. In the latter case, they may choose to initialize all lines | 
|---|
| 470 | *  first, or only initialize the remaining lines after the first call. | 
|---|
| 471 | * | 
|---|
| 472 | *  @param rowsDecoded Optional output variable returning the total number of | 
|---|
| 473 | *      lines initialized. Only meaningful if this method returns kIncompleteInput. | 
|---|
| 474 | *      Otherwise the implementation may not set it. | 
|---|
| 475 | *      Note that some implementations may have initialized this many rows, but | 
|---|
| 476 | *      not necessarily finished those rows (e.g. interlaced PNG). This may be | 
|---|
| 477 | *      useful for determining what rows the client needs to initialize. | 
|---|
| 478 | *  @return kSuccess if all lines requested in startIncrementalDecode have | 
|---|
| 479 | *      been completely decoded. kIncompleteInput otherwise. | 
|---|
| 480 | */ | 
|---|
| 481 | Result incrementalDecode(int* rowsDecoded = nullptr) { | 
|---|
| 482 | if (!fStartedIncrementalDecode) { | 
|---|
| 483 | return kInvalidParameters; | 
|---|
| 484 | } | 
|---|
| 485 | return this->onIncrementalDecode(rowsDecoded); | 
|---|
| 486 | } | 
|---|
| 487 |  | 
|---|
| 488 | /** | 
|---|
| 489 | * The remaining functions revolve around decoding scanlines. | 
|---|
| 490 | */ | 
|---|
| 491 |  | 
|---|
| 492 | /** | 
|---|
| 493 | *  Prepare for a scanline decode with the specified options. | 
|---|
| 494 | * | 
|---|
| 495 | *  After this call, this class will be ready to decode the first scanline. | 
|---|
| 496 | * | 
|---|
| 497 | *  This must be called in order to call getScanlines or skipScanlines. | 
|---|
| 498 | * | 
|---|
| 499 | *  This may require rewinding the stream. | 
|---|
| 500 | * | 
|---|
| 501 | *  Not all SkCodecs support this. | 
|---|
| 502 | * | 
|---|
| 503 | *  @param dstInfo Info of the destination. If the dimensions do not match | 
|---|
| 504 | *      those of getInfo, this implies a scale. | 
|---|
| 505 | *  @param options Contains decoding options, including if memory is zero | 
|---|
| 506 | *      initialized. | 
|---|
| 507 | *  @return Enum representing success or reason for failure. | 
|---|
| 508 | */ | 
|---|
| 509 | Result startScanlineDecode(const SkImageInfo& dstInfo, const Options* options); | 
|---|
| 510 |  | 
|---|
| 511 | /** | 
|---|
| 512 | *  Simplified version of startScanlineDecode() that uses the default Options. | 
|---|
| 513 | */ | 
|---|
| 514 | Result startScanlineDecode(const SkImageInfo& dstInfo) { | 
|---|
| 515 | return this->startScanlineDecode(dstInfo, nullptr); | 
|---|
| 516 | } | 
|---|
| 517 |  | 
|---|
| 518 | /** | 
|---|
| 519 | *  Write the next countLines scanlines into dst. | 
|---|
| 520 | * | 
|---|
| 521 | *  Not valid to call before calling startScanlineDecode(). | 
|---|
| 522 | * | 
|---|
| 523 | *  @param dst Must be non-null, and large enough to hold countLines | 
|---|
| 524 | *      scanlines of size rowBytes. | 
|---|
| 525 | *  @param countLines Number of lines to write. | 
|---|
| 526 | *  @param rowBytes Number of bytes per row. Must be large enough to hold | 
|---|
| 527 | *      a scanline based on the SkImageInfo used to create this object. | 
|---|
| 528 | *  @return the number of lines successfully decoded.  If this value is | 
|---|
| 529 | *      less than countLines, this will fill the remaining lines with a | 
|---|
| 530 | *      default value. | 
|---|
| 531 | */ | 
|---|
| 532 | int getScanlines(void* dst, int countLines, size_t rowBytes); | 
|---|
| 533 |  | 
|---|
| 534 | /** | 
|---|
| 535 | *  Skip count scanlines. | 
|---|
| 536 | * | 
|---|
| 537 | *  Not valid to call before calling startScanlineDecode(). | 
|---|
| 538 | * | 
|---|
| 539 | *  The default version just calls onGetScanlines and discards the dst. | 
|---|
| 540 | *  NOTE: If skipped lines are the only lines with alpha, this default | 
|---|
| 541 | *  will make reallyHasAlpha return true, when it could have returned | 
|---|
| 542 | *  false. | 
|---|
| 543 | * | 
|---|
| 544 | *  @return true if the scanlines were successfully skipped | 
|---|
| 545 | *          false on failure, possible reasons for failure include: | 
|---|
| 546 | *              An incomplete input image stream. | 
|---|
| 547 | *              Calling this function before calling startScanlineDecode(). | 
|---|
| 548 | *              If countLines is less than zero or so large that it moves | 
|---|
| 549 | *                  the current scanline past the end of the image. | 
|---|
| 550 | */ | 
|---|
| 551 | bool skipScanlines(int countLines); | 
|---|
| 552 |  | 
|---|
| 553 | /** | 
|---|
| 554 | *  The order in which rows are output from the scanline decoder is not the | 
|---|
| 555 | *  same for all variations of all image types.  This explains the possible | 
|---|
| 556 | *  output row orderings. | 
|---|
| 557 | */ | 
|---|
| 558 | enum SkScanlineOrder { | 
|---|
| 559 | /* | 
|---|
| 560 | * By far the most common, this indicates that the image can be decoded | 
|---|
| 561 | * reliably using the scanline decoder, and that rows will be output in | 
|---|
| 562 | * the logical order. | 
|---|
| 563 | */ | 
|---|
| 564 | kTopDown_SkScanlineOrder, | 
|---|
| 565 |  | 
|---|
| 566 | /* | 
|---|
| 567 | * This indicates that the scanline decoder reliably outputs rows, but | 
|---|
| 568 | * they will be returned in reverse order.  If the scanline format is | 
|---|
| 569 | * kBottomUp, the nextScanline() API can be used to determine the actual | 
|---|
| 570 | * y-coordinate of the next output row, but the client is not forced | 
|---|
| 571 | * to take advantage of this, given that it's not too tough to keep | 
|---|
| 572 | * track independently. | 
|---|
| 573 | * | 
|---|
| 574 | * For full image decodes, it is safe to get all of the scanlines at | 
|---|
| 575 | * once, since the decoder will handle inverting the rows as it | 
|---|
| 576 | * decodes. | 
|---|
| 577 | * | 
|---|
| 578 | * For subset decodes and sampling, it is simplest to get and skip | 
|---|
| 579 | * scanlines one at a time, using the nextScanline() API.  It is | 
|---|
| 580 | * possible to ask for larger chunks at a time, but this should be used | 
|---|
| 581 | * with caution.  As with full image decodes, the decoder will handle | 
|---|
| 582 | * inverting the requested rows, but rows will still be delivered | 
|---|
| 583 | * starting from the bottom of the image. | 
|---|
| 584 | * | 
|---|
| 585 | * Upside down bmps are an example. | 
|---|
| 586 | */ | 
|---|
| 587 | kBottomUp_SkScanlineOrder, | 
|---|
| 588 | }; | 
|---|
| 589 |  | 
|---|
| 590 | /** | 
|---|
| 591 | *  An enum representing the order in which scanlines will be returned by | 
|---|
| 592 | *  the scanline decoder. | 
|---|
| 593 | * | 
|---|
| 594 | *  This is undefined before startScanlineDecode() is called. | 
|---|
| 595 | */ | 
|---|
| 596 | SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); } | 
|---|
| 597 |  | 
|---|
| 598 | /** | 
|---|
| 599 | *  Returns the y-coordinate of the next row to be returned by the scanline | 
|---|
| 600 | *  decoder. | 
|---|
| 601 | * | 
|---|
| 602 | *  This will equal fCurrScanline, except in the case of strangely | 
|---|
| 603 | *  encoded image types (bottom-up bmps). | 
|---|
| 604 | * | 
|---|
| 605 | *  Results are undefined when not in scanline decoding mode. | 
|---|
| 606 | */ | 
|---|
| 607 | int nextScanline() const { return this->outputScanline(fCurrScanline); } | 
|---|
| 608 |  | 
|---|
| 609 | /** | 
|---|
| 610 | *  Returns the output y-coordinate of the row that corresponds to an input | 
|---|
| 611 | *  y-coordinate.  The input y-coordinate represents where the scanline | 
|---|
| 612 | *  is located in the encoded data. | 
|---|
| 613 | * | 
|---|
| 614 | *  This will equal inputScanline, except in the case of strangely | 
|---|
| 615 | *  encoded image types (bottom-up bmps, interlaced gifs). | 
|---|
| 616 | */ | 
|---|
| 617 | int outputScanline(int inputScanline) const; | 
|---|
| 618 |  | 
|---|
| 619 | /** | 
|---|
| 620 | *  Return the number of frames in the image. | 
|---|
| 621 | * | 
|---|
| 622 | *  May require reading through the stream. | 
|---|
| 623 | */ | 
|---|
| 624 | int getFrameCount() { | 
|---|
| 625 | return this->onGetFrameCount(); | 
|---|
| 626 | } | 
|---|
| 627 |  | 
|---|
| 628 | // Sentinel value used when a frame index implies "no frame": | 
|---|
| 629 | // - FrameInfo::fRequiredFrame set to this value means the frame | 
|---|
| 630 | //   is independent. | 
|---|
| 631 | // - Options::fPriorFrame set to this value means no (relevant) prior frame | 
|---|
| 632 | //   is residing in dst's memory. | 
|---|
| 633 | static constexpr int kNoFrame = -1; | 
|---|
| 634 |  | 
|---|
| 635 | // This transitional definition was added in August 2018, and will eventually be removed. | 
|---|
| 636 | #ifdef SK_LEGACY_SKCODEC_NONE_ENUM | 
|---|
| 637 | static constexpr int kNone = kNoFrame; | 
|---|
| 638 | #endif | 
|---|
| 639 |  | 
|---|
| 640 | /** | 
|---|
| 641 | *  Information about individual frames in a multi-framed image. | 
|---|
| 642 | */ | 
|---|
| 643 | struct FrameInfo { | 
|---|
| 644 | /** | 
|---|
| 645 | *  The frame that this frame needs to be blended with, or | 
|---|
| 646 | *  kNoFrame if this frame is independent (so it can be | 
|---|
| 647 | *  drawn over an uninitialized buffer). | 
|---|
| 648 | * | 
|---|
| 649 | *  Note that this is the *earliest* frame that can be used | 
|---|
| 650 | *  for blending. Any frame from [fRequiredFrame, i) can be | 
|---|
| 651 | *  used, unless its fDisposalMethod is kRestorePrevious. | 
|---|
| 652 | */ | 
|---|
| 653 | int fRequiredFrame; | 
|---|
| 654 |  | 
|---|
| 655 | /** | 
|---|
| 656 | *  Number of milliseconds to show this frame. | 
|---|
| 657 | */ | 
|---|
| 658 | int fDuration; | 
|---|
| 659 |  | 
|---|
| 660 | /** | 
|---|
| 661 | *  Whether the end marker for this frame is contained in the stream. | 
|---|
| 662 | * | 
|---|
| 663 | *  Note: this does not guarantee that an attempt to decode will be complete. | 
|---|
| 664 | *  There could be an error in the stream. | 
|---|
| 665 | */ | 
|---|
| 666 | bool fFullyReceived; | 
|---|
| 667 |  | 
|---|
| 668 | /** | 
|---|
| 669 | *  This is conservative; it will still return non-opaque if e.g. a | 
|---|
| 670 | *  color index-based frame has a color with alpha but does not use it. | 
|---|
| 671 | */ | 
|---|
| 672 | SkAlphaType fAlphaType; | 
|---|
| 673 |  | 
|---|
| 674 | /** | 
|---|
| 675 | *  How this frame should be modified before decoding the next one. | 
|---|
| 676 | */ | 
|---|
| 677 | SkCodecAnimation::DisposalMethod fDisposalMethod; | 
|---|
| 678 | }; | 
|---|
| 679 |  | 
|---|
| 680 | /** | 
|---|
| 681 | *  Return info about a single frame. | 
|---|
| 682 | * | 
|---|
| 683 | *  Only supported by multi-frame images. Does not read through the stream, | 
|---|
| 684 | *  so it should be called after getFrameCount() to parse any frames that | 
|---|
| 685 | *  have not already been parsed. | 
|---|
| 686 | */ | 
|---|
| 687 | bool getFrameInfo(int index, FrameInfo* info) const { | 
|---|
| 688 | if (index < 0) { | 
|---|
| 689 | return false; | 
|---|
| 690 | } | 
|---|
| 691 | return this->onGetFrameInfo(index, info); | 
|---|
| 692 | } | 
|---|
| 693 |  | 
|---|
| 694 | /** | 
|---|
| 695 | *  Return info about all the frames in the image. | 
|---|
| 696 | * | 
|---|
| 697 | *  May require reading through the stream to determine info about the | 
|---|
| 698 | *  frames (including the count). | 
|---|
| 699 | * | 
|---|
| 700 | *  As such, future decoding calls may require a rewind. | 
|---|
| 701 | * | 
|---|
| 702 | *  For still (non-animated) image codecs, this will return an empty vector. | 
|---|
| 703 | */ | 
|---|
| 704 | std::vector<FrameInfo> getFrameInfo(); | 
|---|
| 705 |  | 
|---|
| 706 | static constexpr int kRepetitionCountInfinite = -1; | 
|---|
| 707 |  | 
|---|
| 708 | /** | 
|---|
| 709 | *  Return the number of times to repeat, if this image is animated. This number does not | 
|---|
| 710 | *  include the first play through of each frame. For example, a repetition count of 4 means | 
|---|
| 711 | *  that each frame is played 5 times and then the animation stops. | 
|---|
| 712 | * | 
|---|
| 713 | *  It can return kRepetitionCountInfinite, a negative number, meaning that the animation | 
|---|
| 714 | *  should loop forever. | 
|---|
| 715 | * | 
|---|
| 716 | *  May require reading the stream to find the repetition count. | 
|---|
| 717 | * | 
|---|
| 718 | *  As such, future decoding calls may require a rewind. | 
|---|
| 719 | * | 
|---|
| 720 | *  For still (non-animated) image codecs, this will return 0. | 
|---|
| 721 | */ | 
|---|
| 722 | int getRepetitionCount() { | 
|---|
| 723 | return this->onGetRepetitionCount(); | 
|---|
| 724 | } | 
|---|
| 725 |  | 
|---|
| 726 | // Register a decoder at runtime by passing two function pointers: | 
|---|
| 727 | //    - peek() to return true if the span of bytes appears to be your encoded format; | 
|---|
| 728 | //    - make() to attempt to create an SkCodec from the given stream. | 
|---|
| 729 | // Not thread safe. | 
|---|
| 730 | static void Register( | 
|---|
| 731 | bool                     (*peek)(const void*, size_t), | 
|---|
| 732 | std::unique_ptr<SkCodec> (*make)(std::unique_ptr<SkStream>, SkCodec::Result*)); | 
|---|
| 733 |  | 
|---|
| 734 | protected: | 
|---|
| 735 | const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; } | 
|---|
| 736 |  | 
|---|
| 737 | using XformFormat = skcms_PixelFormat; | 
|---|
| 738 |  | 
|---|
| 739 | SkCodec(SkEncodedInfo&&, | 
|---|
| 740 | XformFormat srcFormat, | 
|---|
| 741 | std::unique_ptr<SkStream>, | 
|---|
| 742 | SkEncodedOrigin = kTopLeft_SkEncodedOrigin); | 
|---|
| 743 |  | 
|---|
| 744 | virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const { | 
|---|
| 745 | // By default, scaling is not supported. | 
|---|
| 746 | return this->dimensions(); | 
|---|
| 747 | } | 
|---|
| 748 |  | 
|---|
| 749 | // FIXME: What to do about subsets?? | 
|---|
| 750 | /** | 
|---|
| 751 | *  Subclasses should override if they support dimensions other than the | 
|---|
| 752 | *  srcInfo's. | 
|---|
| 753 | */ | 
|---|
| 754 | virtual bool onDimensionsSupported(const SkISize&) { | 
|---|
| 755 | return false; | 
|---|
| 756 | } | 
|---|
| 757 |  | 
|---|
| 758 | virtual SkEncodedImageFormat onGetEncodedFormat() const = 0; | 
|---|
| 759 |  | 
|---|
| 760 | /** | 
|---|
| 761 | * @param rowsDecoded When the encoded image stream is incomplete, this function | 
|---|
| 762 | *                    will return kIncompleteInput and rowsDecoded will be set to | 
|---|
| 763 | *                    the number of scanlines that were successfully decoded. | 
|---|
| 764 | *                    This will allow getPixels() to fill the uninitialized memory. | 
|---|
| 765 | */ | 
|---|
| 766 | virtual Result onGetPixels(const SkImageInfo& info, | 
|---|
| 767 | void* pixels, size_t rowBytes, const Options&, | 
|---|
| 768 | int* rowsDecoded) = 0; | 
|---|
| 769 |  | 
|---|
| 770 | virtual bool onQueryYUV8(SkYUVASizeInfo*, SkYUVColorSpace*) const { | 
|---|
| 771 | return false; | 
|---|
| 772 | } | 
|---|
| 773 |  | 
|---|
| 774 | virtual Result onGetYUV8Planes(const SkYUVASizeInfo&, | 
|---|
| 775 | void*[SkYUVASizeInfo::kMaxCount] /*planes*/) { | 
|---|
| 776 | return kUnimplemented; | 
|---|
| 777 | } | 
|---|
| 778 |  | 
|---|
| 779 | virtual bool onGetValidSubset(SkIRect* /*desiredSubset*/) const { | 
|---|
| 780 | // By default, subsets are not supported. | 
|---|
| 781 | return false; | 
|---|
| 782 | } | 
|---|
| 783 |  | 
|---|
| 784 | /** | 
|---|
| 785 | *  If the stream was previously read, attempt to rewind. | 
|---|
| 786 | * | 
|---|
| 787 | *  If the stream needed to be rewound, call onRewind. | 
|---|
| 788 | *  @returns true if the codec is at the right position and can be used. | 
|---|
| 789 | *      false if there was a failure to rewind. | 
|---|
| 790 | * | 
|---|
| 791 | *  This is called by getPixels(), getYUV8Planes(), startIncrementalDecode() and | 
|---|
| 792 | *  startScanlineDecode(). Subclasses may call if they need to rewind at another time. | 
|---|
| 793 | */ | 
|---|
| 794 | bool SK_WARN_UNUSED_RESULT rewindIfNeeded(); | 
|---|
| 795 |  | 
|---|
| 796 | /** | 
|---|
| 797 | *  Called by rewindIfNeeded, if the stream needed to be rewound. | 
|---|
| 798 | * | 
|---|
| 799 | *  Subclasses should do any set up needed after a rewind. | 
|---|
| 800 | */ | 
|---|
| 801 | virtual bool onRewind() { | 
|---|
| 802 | return true; | 
|---|
| 803 | } | 
|---|
| 804 |  | 
|---|
| 805 | /** | 
|---|
| 806 | * Get method for the input stream | 
|---|
| 807 | */ | 
|---|
| 808 | SkStream* stream() { | 
|---|
| 809 | return fStream.get(); | 
|---|
| 810 | } | 
|---|
| 811 |  | 
|---|
| 812 | /** | 
|---|
| 813 | *  The remaining functions revolve around decoding scanlines. | 
|---|
| 814 | */ | 
|---|
| 815 |  | 
|---|
| 816 | /** | 
|---|
| 817 | *  Most images types will be kTopDown and will not need to override this function. | 
|---|
| 818 | */ | 
|---|
| 819 | virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; } | 
|---|
| 820 |  | 
|---|
| 821 | const SkImageInfo& dstInfo() const { return fDstInfo; } | 
|---|
| 822 |  | 
|---|
| 823 | const Options& options() const { return fOptions; } | 
|---|
| 824 |  | 
|---|
| 825 | /** | 
|---|
| 826 | *  Returns the number of scanlines that have been decoded so far. | 
|---|
| 827 | *  This is unaffected by the SkScanlineOrder. | 
|---|
| 828 | * | 
|---|
| 829 | *  Returns -1 if we have not started a scanline decode. | 
|---|
| 830 | */ | 
|---|
| 831 | int currScanline() const { return fCurrScanline; } | 
|---|
| 832 |  | 
|---|
| 833 | virtual int onOutputScanline(int inputScanline) const; | 
|---|
| 834 |  | 
|---|
| 835 | /** | 
|---|
| 836 | *  Return whether we can convert to dst. | 
|---|
| 837 | * | 
|---|
| 838 | *  Will be called for the appropriate frame, prior to initializing the colorXform. | 
|---|
| 839 | */ | 
|---|
| 840 | virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, | 
|---|
| 841 | bool needsColorXform); | 
|---|
| 842 |  | 
|---|
| 843 | // Some classes never need a colorXform e.g. | 
|---|
| 844 | // - ICO uses its embedded codec's colorXform | 
|---|
| 845 | // - WBMP is just Black/White | 
|---|
| 846 | virtual bool usesColorXform() const { return true; } | 
|---|
| 847 | void applyColorXform(void* dst, const void* src, int count) const; | 
|---|
| 848 |  | 
|---|
| 849 | bool colorXform() const { return fXformTime != kNo_XformTime; } | 
|---|
| 850 | bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; } | 
|---|
| 851 |  | 
|---|
| 852 | virtual int onGetFrameCount() { | 
|---|
| 853 | return 1; | 
|---|
| 854 | } | 
|---|
| 855 |  | 
|---|
| 856 | virtual bool onGetFrameInfo(int, FrameInfo*) const { | 
|---|
| 857 | return false; | 
|---|
| 858 | } | 
|---|
| 859 |  | 
|---|
| 860 | virtual int onGetRepetitionCount() { | 
|---|
| 861 | return 0; | 
|---|
| 862 | } | 
|---|
| 863 |  | 
|---|
| 864 | private: | 
|---|
| 865 | const SkEncodedInfo                fEncodedInfo; | 
|---|
| 866 | const XformFormat                  fSrcXformFormat; | 
|---|
| 867 | std::unique_ptr<SkStream>          fStream; | 
|---|
| 868 | bool                               fNeedsRewind; | 
|---|
| 869 | const SkEncodedOrigin              fOrigin; | 
|---|
| 870 |  | 
|---|
| 871 | SkImageInfo                        fDstInfo; | 
|---|
| 872 | Options                            fOptions; | 
|---|
| 873 |  | 
|---|
| 874 | enum XformTime { | 
|---|
| 875 | kNo_XformTime, | 
|---|
| 876 | kPalette_XformTime, | 
|---|
| 877 | kDecodeRow_XformTime, | 
|---|
| 878 | }; | 
|---|
| 879 | XformTime                          fXformTime; | 
|---|
| 880 | XformFormat                        fDstXformFormat; // Based on fDstInfo. | 
|---|
| 881 | skcms_ICCProfile                   fDstProfile; | 
|---|
| 882 | skcms_AlphaFormat                  fDstXformAlphaFormat; | 
|---|
| 883 |  | 
|---|
| 884 | // Only meaningful during scanline decodes. | 
|---|
| 885 | int                                fCurrScanline; | 
|---|
| 886 |  | 
|---|
| 887 | bool                               fStartedIncrementalDecode; | 
|---|
| 888 |  | 
|---|
| 889 | bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque); | 
|---|
| 890 |  | 
|---|
| 891 | /** | 
|---|
| 892 | *  Return whether these dimensions are supported as a scale. | 
|---|
| 893 | * | 
|---|
| 894 | *  The codec may choose to cache the information about scale and subset. | 
|---|
| 895 | *  Either way, the same information will be passed to onGetPixels/onStart | 
|---|
| 896 | *  on success. | 
|---|
| 897 | * | 
|---|
| 898 | *  This must return true for a size returned from getScaledDimensions. | 
|---|
| 899 | */ | 
|---|
| 900 | bool dimensionsSupported(const SkISize& dim) { | 
|---|
| 901 | return dim == this->dimensions() || this->onDimensionsSupported(dim); | 
|---|
| 902 | } | 
|---|
| 903 |  | 
|---|
| 904 | /** | 
|---|
| 905 | *  For multi-framed images, return the object with information about the frames. | 
|---|
| 906 | */ | 
|---|
| 907 | virtual const SkFrameHolder* getFrameHolder() const { | 
|---|
| 908 | return nullptr; | 
|---|
| 909 | } | 
|---|
| 910 |  | 
|---|
| 911 | /** | 
|---|
| 912 | *  Check for a valid Options.fFrameIndex, and decode prior frames if necessary. | 
|---|
| 913 | */ | 
|---|
| 914 | Result handleFrameIndex(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&); | 
|---|
| 915 |  | 
|---|
| 916 | // Methods for scanline decoding. | 
|---|
| 917 | virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/, | 
|---|
| 918 | const Options& /*options*/) { | 
|---|
| 919 | return kUnimplemented; | 
|---|
| 920 | } | 
|---|
| 921 |  | 
|---|
| 922 | virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t, | 
|---|
| 923 | const Options&) { | 
|---|
| 924 | return kUnimplemented; | 
|---|
| 925 | } | 
|---|
| 926 |  | 
|---|
| 927 | virtual Result onIncrementalDecode(int*) { | 
|---|
| 928 | return kUnimplemented; | 
|---|
| 929 | } | 
|---|
| 930 |  | 
|---|
| 931 |  | 
|---|
| 932 | virtual bool onSkipScanlines(int /*countLines*/) { return false; } | 
|---|
| 933 |  | 
|---|
| 934 | virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; } | 
|---|
| 935 |  | 
|---|
| 936 | /** | 
|---|
| 937 | * On an incomplete decode, getPixels() and getScanlines() will call this function | 
|---|
| 938 | * to fill any uinitialized memory. | 
|---|
| 939 | * | 
|---|
| 940 | * @param dstInfo        Contains the destination color type | 
|---|
| 941 | *                       Contains the destination alpha type | 
|---|
| 942 | *                       Contains the destination width | 
|---|
| 943 | *                       The height stored in this info is unused | 
|---|
| 944 | * @param dst            Pointer to the start of destination pixel memory | 
|---|
| 945 | * @param rowBytes       Stride length in destination pixel memory | 
|---|
| 946 | * @param zeroInit       Indicates if memory is zero initialized | 
|---|
| 947 | * @param linesRequested Number of lines that the client requested | 
|---|
| 948 | * @param linesDecoded   Number of lines that were successfully decoded | 
|---|
| 949 | */ | 
|---|
| 950 | void fillIncompleteImage(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, | 
|---|
| 951 | ZeroInitialized zeroInit, int linesRequested, int linesDecoded); | 
|---|
| 952 |  | 
|---|
| 953 | /** | 
|---|
| 954 | *  Return an object which will allow forcing scanline decodes to sample in X. | 
|---|
| 955 | * | 
|---|
| 956 | *  May create a sampler, if one is not currently being used. Otherwise, does | 
|---|
| 957 | *  not affect ownership. | 
|---|
| 958 | * | 
|---|
| 959 | *  Only valid during scanline decoding or incremental decoding. | 
|---|
| 960 | */ | 
|---|
| 961 | virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } | 
|---|
| 962 |  | 
|---|
| 963 | friend class DM::CodecSrc;  // for fillIncompleteImage | 
|---|
| 964 | friend class SkSampledCodec; | 
|---|
| 965 | friend class SkIcoCodec; | 
|---|
| 966 | friend class SkAndroidCodec; // for fEncodedInfo | 
|---|
| 967 | }; | 
|---|
| 968 | #endif // SkCodec_DEFINED | 
|---|
| 969 |  | 
|---|