| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkBmpRLECodec.h" | 8 #include "SkBmpRLECodec.h" |
| 9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 SkCodecPrintf("Error: cannot convert input type to output type.\n"); | 55 SkCodecPrintf("Error: cannot convert input type to output type.\n"); |
| 56 return kInvalidConversion; | 56 return kInvalidConversion; |
| 57 } | 57 } |
| 58 | 58 |
| 59 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); | 59 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); |
| 60 if (kSuccess != result) { | 60 if (kSuccess != result) { |
| 61 return result; | 61 return result; |
| 62 } | 62 } |
| 63 | 63 |
| 64 // Perform the decode | 64 // Perform the decode |
| 65 return this->decodeRows(dstInfo, dst, dstRowBytes, opts); | 65 uint32_t rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); |
| 66 if (rows != dstInfo.height()) { |
| 67 // We do not need to call setIncompleteScanlines() because decodeRows()
will handle |
| 68 // filling the background. |
| 69 return kIncompleteInput; |
| 70 } |
| 66 } | 71 } |
| 67 | 72 |
| 68 /* | 73 /* |
| 69 * Process the color table for the bmp input | 74 * Process the color table for the bmp input |
| 70 */ | 75 */ |
| 71 bool SkBmpRLECodec::createColorTable(int* numColors) { | 76 bool SkBmpRLECodec::createColorTable(int* numColors) { |
| 72 // Allocate memory for color table | 77 // Allocate memory for color table |
| 73 uint32_t colorBytes = 0; | 78 uint32_t colorBytes = 0; |
| 74 SkPMColor colorTable[256]; | 79 SkPMColor colorTable[256]; |
| 75 if (this->bitsPerPixel() <= 8) { | 80 if (this->bitsPerPixel() <= 8) { |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 | 280 |
| 276 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL); | 281 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL); |
| 277 | 282 |
| 278 return SkCodec::kSuccess; | 283 return SkCodec::kSuccess; |
| 279 } | 284 } |
| 280 | 285 |
| 281 /* | 286 /* |
| 282 * Performs the bitmap decoding for RLE input format | 287 * Performs the bitmap decoding for RLE input format |
| 283 * RLE decoding is performed all at once, rather than a one row at a time | 288 * RLE decoding is performed all at once, rather than a one row at a time |
| 284 */ | 289 */ |
| 285 SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo, | 290 uint32_t SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t
dstRowBytes, |
| 286 void* dst, size_t dstRowBytes, | 291 const Options& opts) { |
| 287 const Options& opts) { | |
| 288 // Set RLE flags | 292 // Set RLE flags |
| 289 static const uint8_t RLE_ESCAPE = 0; | 293 static const uint8_t RLE_ESCAPE = 0; |
| 290 static const uint8_t RLE_EOL = 0; | 294 static const uint8_t RLE_EOL = 0; |
| 291 static const uint8_t RLE_EOF = 1; | 295 static const uint8_t RLE_EOF = 1; |
| 292 static const uint8_t RLE_DELTA = 2; | 296 static const uint8_t RLE_DELTA = 2; |
| 293 | 297 |
| 294 // Set constant values | 298 // Set constant values |
| 295 const int width = this->getInfo().width(); | 299 const int width = this->getInfo().width(); |
| 296 const int height = dstInfo.height(); | 300 const int height = dstInfo.height(); |
| 297 | 301 |
| 298 // Destination parameters | 302 // Destination parameters |
| 299 int x = 0; | 303 int x = 0; |
| 300 int y = 0; | 304 int y = 0; |
| 301 | 305 |
| 302 // Set the background as transparent. Then, if the RLE code skips pixels, | 306 // Set the background as transparent. Then, if the RLE code skips pixels, |
| 303 // the skipped pixels will be transparent. | 307 // the skipped pixels will be transparent. |
| 304 // Because of the need for transparent pixels, kN32 is the only color | 308 // Because of the need for transparent pixels, kN32 is the only color |
| 305 // type that makes sense for the destination format. | 309 // type that makes sense for the destination format. |
| 306 SkASSERT(kN32_SkColorType == dstInfo.colorType()); | 310 SkASSERT(kN32_SkColorType == dstInfo.colorType()); |
| 307 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, | 311 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroI
nitialized); |
| 308 NULL, opts.fZeroInitialized); | |
| 309 | 312 |
| 310 while (true) { | 313 while (true) { |
| 311 // If we have reached a row that is beyond the requested height, we have | 314 // If we have reached a row that is beyond the requested height, we have |
| 312 // succeeded. | 315 // succeeded. |
| 313 if (y >= height) { | 316 if (y >= height) { |
| 314 // It would be better to check for the EOF marker before returning | 317 // It would be better to check for the EOF marker before indicating |
| 315 // success, but we may be performing a scanline decode, which | 318 // success, but we may be performing a scanline decode, which |
| 316 // may require us to stop before decoding the full height. | 319 // would require us to stop before decoding the full height. |
| 317 return kSuccess; | 320 return height; |
| 318 } | 321 } |
| 319 | 322 |
| 320 // Every entry takes at least two bytes | 323 // Every entry takes at least two bytes |
| 321 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 324 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
| 322 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); | 325 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); |
| 323 if (this->checkForMoreData() < 2) { | 326 if (this->checkForMoreData() < 2) { |
| 324 return kIncompleteInput; | 327 return y; |
| 325 } | 328 } |
| 326 } | 329 } |
| 327 | 330 |
| 328 // Read the next two bytes. These bytes have different meanings | 331 // Read the next two bytes. These bytes have different meanings |
| 329 // depending on their values. In the first interpretation, the first | 332 // depending on their values. In the first interpretation, the first |
| 330 // byte is an escape flag and the second byte indicates what special | 333 // byte is an escape flag and the second byte indicates what special |
| 331 // task to perform. | 334 // task to perform. |
| 332 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; | 335 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; |
| 333 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; | 336 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; |
| 334 | 337 |
| 335 // Perform decoding | 338 // Perform decoding |
| 336 if (RLE_ESCAPE == flag) { | 339 if (RLE_ESCAPE == flag) { |
| 337 switch (task) { | 340 switch (task) { |
| 338 case RLE_EOL: | 341 case RLE_EOL: |
| 339 x = 0; | 342 x = 0; |
| 340 y++; | 343 y++; |
| 341 break; | 344 break; |
| 342 case RLE_EOF: | 345 case RLE_EOF: |
| 343 return kSuccess; | 346 return kSuccess; |
| 344 case RLE_DELTA: { | 347 case RLE_DELTA: { |
| 345 // Two bytes are needed to specify delta | 348 // Two bytes are needed to specify delta |
| 346 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 349 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
| 347 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); | 350 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); |
| 348 if (this->checkForMoreData() < 2) { | 351 if (this->checkForMoreData() < 2) { |
| 349 return kIncompleteInput; | 352 return y; |
| 350 } | 353 } |
| 351 } | 354 } |
| 352 // Modify x and y | 355 // Modify x and y |
| 353 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; | 356 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; |
| 354 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; | 357 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; |
| 355 x += dx; | 358 x += dx; |
| 356 y += dy; | 359 y += dy; |
| 357 if (x > width || y > height) { | 360 if (x > width || y > height) { |
| 358 SkCodecPrintf("Warning: invalid RLE input.\n"); | 361 SkCodecPrintf("Warning: invalid RLE input.\n"); |
| 359 return kInvalidInput; | 362 return y - dy; |
| 360 } | 363 } |
| 361 break; | 364 break; |
| 362 } | 365 } |
| 363 default: { | 366 default: { |
| 364 // If task does not match any of the above signals, it | 367 // If task does not match any of the above signals, it |
| 365 // indicates that we have a sequence of non-RLE pixels. | 368 // indicates that we have a sequence of non-RLE pixels. |
| 366 // Furthermore, the value of task is equal to the number | 369 // Furthermore, the value of task is equal to the number |
| 367 // of pixels to interpret. | 370 // of pixels to interpret. |
| 368 uint8_t numPixels = task; | 371 uint8_t numPixels = task; |
| 369 const size_t rowBytes = compute_row_bytes(numPixels, | 372 const size_t rowBytes = compute_row_bytes(numPixels, |
| 370 this->bitsPerPixel()); | 373 this->bitsPerPixel()); |
| 371 // Abort if setting numPixels moves us off the edge of the | 374 // Abort if setting numPixels moves us off the edge of the |
| 372 // image. | 375 // image. |
| 373 if (x + numPixels > width) { | 376 if (x + numPixels > width) { |
| 374 SkCodecPrintf("Warning: invalid RLE input.\n"); | 377 SkCodecPrintf("Warning: invalid RLE input.\n"); |
| 375 return kInvalidInput; | 378 return y; |
| 376 } | 379 } |
| 377 // Also abort if there are not enough bytes | 380 // Also abort if there are not enough bytes |
| 378 // remaining in the stream to set numPixels. | 381 // remaining in the stream to set numPixels. |
| 379 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { | 382 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { |
| 380 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); | 383 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); |
| 381 if (this->checkForMoreData() < SkAlign2(rowBytes)) { | 384 if (this->checkForMoreData() < SkAlign2(rowBytes)) { |
| 382 return kIncompleteInput; | 385 return y; |
| 383 } | 386 } |
| 384 } | 387 } |
| 385 // Set numPixels number of pixels | 388 // Set numPixels number of pixels |
| 386 while (numPixels > 0) { | 389 while (numPixels > 0) { |
| 387 switch(this->bitsPerPixel()) { | 390 switch(this->bitsPerPixel()) { |
| 388 case 4: { | 391 case 4: { |
| 389 SkASSERT(fCurrRLEByte < fRLEBytes); | 392 SkASSERT(fCurrRLEByte < fRLEBytes); |
| 390 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++
]; | 393 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++
]; |
| 391 setPixel(dst, dstRowBytes, dstInfo, x++, | 394 setPixel(dst, dstRowBytes, dstInfo, x++, |
| 392 y, val >> 4); | 395 y, val >> 4); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 408 SkASSERT(fCurrRLEByte + 2 < fRLEBytes); | 411 SkASSERT(fCurrRLEByte + 2 < fRLEBytes); |
| 409 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+
+]; | 412 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+
+]; |
| 410 uint8_t green = fStreamBuffer.get()[fCurrRLEByte
++]; | 413 uint8_t green = fStreamBuffer.get()[fCurrRLEByte
++]; |
| 411 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++
]; | 414 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++
]; |
| 412 setRGBPixel(dst, dstRowBytes, dstInfo, | 415 setRGBPixel(dst, dstRowBytes, dstInfo, |
| 413 x++, y, red, green, blue); | 416 x++, y, red, green, blue); |
| 414 numPixels--; | 417 numPixels--; |
| 415 } | 418 } |
| 416 default: | 419 default: |
| 417 SkASSERT(false); | 420 SkASSERT(false); |
| 418 return kInvalidInput; | 421 return y; |
| 419 } | 422 } |
| 420 } | 423 } |
| 421 // Skip a byte if necessary to maintain alignment | 424 // Skip a byte if necessary to maintain alignment |
| 422 if (!SkIsAlign2(rowBytes)) { | 425 if (!SkIsAlign2(rowBytes)) { |
| 423 fCurrRLEByte++; | 426 fCurrRLEByte++; |
| 424 } | 427 } |
| 425 break; | 428 break; |
| 426 } | 429 } |
| 427 } | 430 } |
| 428 } else { | 431 } else { |
| 429 // If the first byte read is not a flag, it indicates the number of | 432 // If the first byte read is not a flag, it indicates the number of |
| 430 // pixels to set in RLE mode. | 433 // pixels to set in RLE mode. |
| 431 const uint8_t numPixels = flag; | 434 const uint8_t numPixels = flag; |
| 432 const int endX = SkTMin<int>(x + numPixels, width); | 435 const int endX = SkTMin<int>(x + numPixels, width); |
| 433 | 436 |
| 434 if (24 == this->bitsPerPixel()) { | 437 if (24 == this->bitsPerPixel()) { |
| 435 // In RLE24, the second byte read is part of the pixel color. | 438 // In RLE24, the second byte read is part of the pixel color. |
| 436 // There are two more required bytes to finish encoding the | 439 // There are two more required bytes to finish encoding the |
| 437 // color. | 440 // color. |
| 438 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 441 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
| 439 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); | 442 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); |
| 440 if (this->checkForMoreData() < 2) { | 443 if (this->checkForMoreData() < 2) { |
| 441 return kIncompleteInput; | 444 return y; |
| 442 } | 445 } |
| 443 } | 446 } |
| 444 | 447 |
| 445 // Fill the pixels up to endX with the specified color | 448 // Fill the pixels up to endX with the specified color |
| 446 uint8_t blue = task; | 449 uint8_t blue = task; |
| 447 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; | 450 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; |
| 448 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; | 451 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; |
| 449 while (x < endX) { | 452 while (x < endX) { |
| 450 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b
lue); | 453 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b
lue); |
| 451 } | 454 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 463 | 466 |
| 464 // Set the indicated number of pixels | 467 // Set the indicated number of pixels |
| 465 for (int which = 0; x < endX; x++) { | 468 for (int which = 0; x < endX; x++) { |
| 466 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); | 469 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); |
| 467 which = !which; | 470 which = !which; |
| 468 } | 471 } |
| 469 } | 472 } |
| 470 } | 473 } |
| 471 } | 474 } |
| 472 } | 475 } |
| OLD | NEW |