 Chromium Code Reviews
 Chromium Code Reviews Issue 1472933002:
  Make SkAndroidCodec support ico  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 1472933002:
  Make SkAndroidCodec support ico  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| 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 "SkBmpStandardCodec.h" | 8 #include "SkBmpStandardCodec.h" | 
| 9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" | 
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" | 
| 11 #include "SkStream.h" | 11 #include "SkStream.h" | 
| 12 | 12 | 
| 13 /* | 13 /* | 
| 14 * Creates an instance of the decoder | 14 * Creates an instance of the decoder | 
| 15 * Called only by NewFromStream | 15 * Called only by NewFromStream | 
| 16 */ | 16 */ | 
| 17 SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream , | 17 SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream , | 
| 18 uint16_t bitsPerPixel, uint32_t numColors , | 18 uint16_t bitsPerPixel, uint32_t numColors , | 
| 19 uint32_t bytesPerColor, uint32_t offset, | 19 uint32_t bytesPerColor, uint32_t offset, | 
| 20 SkCodec::SkScanlineOrder rowOrder, bool i nIco) | 20 SkCodec::SkScanlineOrder rowOrder, bool i nIco) | 
| 21 : INHERITED(info, stream, bitsPerPixel, rowOrder) | 21 : INHERITED(info, stream, bitsPerPixel, rowOrder) | 
| 22 , fColorTable(nullptr) | 22 , fColorTable(nullptr) | 
| 23 , fNumColors(this->computeNumColors(numColors)) | 23 , fNumColors(this->computeNumColors(numColors)) | 
| 24 , fBytesPerColor(bytesPerColor) | 24 , fBytesPerColor(bytesPerColor) | 
| 25 , fOffset(offset) | 25 , fOffset(offset) | 
| 26 , fSwizzler(nullptr) | 26 , fSwizzler(nullptr) | 
| 27 , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bit sPerPixel()))) | 27 , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bit sPerPixel()))) | 
| 28 , fSrcBuffer(new uint8_t [fSrcRowBytes]) | 28 , fSrcBuffer(new uint8_t [fSrcRowBytes]) | 
| 29 , fInIco(inIco) | 29 , fInIco(inIco) | 
| 30 , fAndMaskRowBytes(fInIco ? SkAlign4(compute_row_bytes(this->getInfo().width (), 1)) : 0) | |
| 30 {} | 31 {} | 
| 31 | 32 | 
| 32 /* | 33 /* | 
| 33 * Initiates the bitmap decode | 34 * Initiates the bitmap decode | 
| 34 */ | 35 */ | 
| 35 SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, | 36 SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, | 
| 36 void* dst, size_t dstRowBytes, | 37 void* dst, size_t dstRowBytes, | 
| 37 const Options& opts, | 38 const Options& opts, | 
| 38 SkPMColor* inputColorPtr, | 39 SkPMColor* inputColorPtr, | 
| 39 int* inputColorCount, | 40 int* inputColorCount, | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 53 | 54 | 
| 54 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol orCount); | 55 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol orCount); | 
| 55 if (kSuccess != result) { | 56 if (kSuccess != result) { | 
| 56 return result; | 57 return result; | 
| 57 } | 58 } | 
| 58 int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); | 59 int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); | 
| 59 if (rows != dstInfo.height()) { | 60 if (rows != dstInfo.height()) { | 
| 60 *rowsDecoded = rows; | 61 *rowsDecoded = rows; | 
| 61 return kIncompleteInput; | 62 return kIncompleteInput; | 
| 62 } | 63 } | 
| 63 if (fInIco) { | |
| 64 return this->decodeIcoMask(dstInfo, dst, dstRowBytes); | |
| 65 } | |
| 66 return kSuccess; | 64 return kSuccess; | 
| 67 } | 65 } | 
| 68 | 66 | 
| 69 /* | 67 /* | 
| 70 * Process the color table for the bmp input | 68 * Process the color table for the bmp input | 
| 71 */ | 69 */ | 
| 72 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors ) { | 70 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors ) { | 
| 73 // Allocate memory for color table | 71 // Allocate memory for color table | 
| 74 uint32_t colorBytes = 0; | 72 uint32_t colorBytes = 0; | 
| 75 SkPMColor colorTable[256]; | 73 SkPMColor colorTable[256]; | 
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 if (!this->initializeSwizzler(dstInfo, options)) { | 218 if (!this->initializeSwizzler(dstInfo, options)) { | 
| 221 SkCodecPrintf("Error: cannot initialize swizzler.\n"); | 219 SkCodecPrintf("Error: cannot initialize swizzler.\n"); | 
| 222 return SkCodec::kInvalidConversion; | 220 return SkCodec::kInvalidConversion; | 
| 223 } | 221 } | 
| 224 return SkCodec::kSuccess; | 222 return SkCodec::kSuccess; | 
| 225 } | 223 } | 
| 226 | 224 | 
| 227 /* | 225 /* | 
| 228 * Performs the bitmap decoding for standard input format | 226 * Performs the bitmap decoding for standard input format | 
| 229 */ | 227 */ | 
| 230 int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, | 228 int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, | 
| 231 void* dst, size_t dstRowBytes, | 229 const Options& opts) { | 
| 232 const Options& opts) { | |
| 233 // Iterate over rows of the image | 230 // Iterate over rows of the image | 
| 234 const int height = dstInfo.height(); | 231 const int height = dstInfo.height(); | 
| 235 for (int y = 0; y < height; y++) { | 232 for (int y = 0; y < height; y++) { | 
| 236 // Read a row of the input | 233 // Read a row of the input | 
| 237 if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes ) { | 234 if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes ) { | 
| 238 SkCodecPrintf("Warning: incomplete input stream.\n"); | 235 SkCodecPrintf("Warning: incomplete input stream.\n"); | 
| 239 return y; | 236 return y; | 
| 240 } | 237 } | 
| 241 | 238 | 
| 242 // Decode the row in destination format | 239 // Decode the row in destination format | 
| 243 uint32_t row = this->getDstRow(y, dstInfo.height()); | 240 uint32_t row = this->getDstRow(y, dstInfo.height()); | 
| 244 | 241 | 
| 245 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); | 242 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); | 
| 246 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 243 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 
| 247 } | 244 } | 
| 248 | 245 | 
| 249 // Finished decoding the entire image | 246 if (fInIco) { | 
| 247 const int startScanline = this->currScanline(); | |
| 248 if (startScanline < 0) { | |
| 249 // We are not performing a scanline decode. | |
| 250 // Just decode the entire ICO mask and return. | |
| 251 decodeIcoMask(this->stream(), dstInfo, dst, dstRowBytes); | |
| 252 return height; | |
| 253 } | |
| 254 | |
| 255 // In order to perform a scanline ICO decode, we must be able | |
| 256 // to skip ahead in the stream in order to apply the AND mask | |
| 257 // to the requested scanlines. | |
| 258 // We will do this by taking advantage of the fact that | |
| 259 // SkIcoCodec always uses a SkMemoryStream as its underlying | |
| 260 // representation of the stream. | |
| 261 const void* memoryBase = this->stream()->getMemoryBase(); | |
| 262 SkASSERT(nullptr != memoryBase); | |
| 263 const size_t length = this->stream()->getLength(); | |
| 264 SkASSERT(this->stream()->hasLength()); | |
| 
scroggo
2015/12/03 19:39:25
I think this belongs above the call to getLength
 
msarett
2015/12/03 19:54:15
Done.
 | |
| 265 const size_t currPosition = this->stream()->getPosition(); | |
| 266 SkASSERT(this->stream()->hasPosition()); | |
| 
scroggo
2015/12/03 19:39:24
Same here. Maybe put all the SkASSERTs together? I
 
msarett
2015/12/03 19:54:15
sgtm
 | |
| 267 | |
| 268 // Calculate how many bytes we must skip to reach the AND mask. | |
| 269 const int remainingScanlines = this->getInfo().height() - startScanline - height; | |
| 270 const size_t bytesToSkip = remainingScanlines * fSrcRowBytes + | |
| 271 startScanline * fAndMaskRowBytes; | |
| 272 const size_t subStreamStartPosition = currPosition + bytesToSkip; | |
| 273 if (subStreamStartPosition >= length) { | |
| 274 // FIXME: How can we indicate that this decode was actually incomple te? | |
| 275 return height; | |
| 276 } | |
| 277 | |
| 278 // Create a subStream to pass to decodeIcoMask(). It is useful to encap sulate | |
| 279 // the memory base into a stream in order to safely handle incomplete im ages | |
| 280 // without reading out of bounds memory. | |
| 281 const void* subStreamMemoryBase = SkTAddOffset<const void>(memoryBase, | |
| 282 subStreamStartPosition); | |
| 283 const size_t subStreamLength = length - subStreamStartPosition; | |
| 284 // This call does not transfer ownership of the subStreamMemoryBase. | |
| 285 SkMemoryStream subStream(subStreamMemoryBase, subStreamLength, false); | |
| 286 | |
| 287 // FIXME: If decodeIcoMask does not succeed, is there a way that we can | |
| 288 // indicate the decode was incomplete? | |
| 289 decodeIcoMask(&subStream, dstInfo, dst, dstRowBytes); | |
| 290 } | |
| 291 | |
| 250 return height; | 292 return height; | 
| 251 } | 293 } | 
| 252 | 294 | 
| 253 // TODO (msarett): This function will need to be modified in order to perform ro w by row decodes | 295 void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI nfo, | 
| 254 // when the Ico scanline decoder is implemented. | |
| 255 SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, | |
| 256 void* dst, size_t dstRowBytes) { | 296 void* dst, size_t dstRowBytes) { | 
| 257 // BMP in ICO have transparency, so this cannot be 565, and this mask | 297 // BMP in ICO have transparency, so this cannot be 565, and this mask | 
| 258 // prevents us from using kIndex8. The below code depends on the output | 298 // prevents us from using kIndex8. The below code depends on the output | 
| 259 // being an SkPMColor. | 299 // being an SkPMColor. | 
| 260 SkASSERT(dstInfo.colorType() == kN32_SkColorType); | 300 SkASSERT(dstInfo.colorType() == kN32_SkColorType); | 
| 261 | 301 | 
| 262 // The AND mask is always 1 bit per pixel | 302 // If we are sampling, make sure that we only mask the sampled pixels. | 
| 263 const int width = this->getInfo().width(); | 303 // We do not need to worry about sampling in the y-dimension because that | 
| 264 const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1)); | 304 // should be handled by SkSampledCodec. | 
| 305 int sampleX = fSwizzler->sampleX(); | |
| 306 int startX = get_start_coord(sampleX); | |
| 265 | 307 | 
| 266 SkPMColor* dstPtr = (SkPMColor*) dst; | 308 SkPMColor* dstPtr = (SkPMColor*) dst; | 
| 267 for (int y = 0; y < dstInfo.height(); y++) { | 309 for (int y = 0; y < dstInfo.height(); y++) { | 
| 268 // The srcBuffer will at least be large enough | 310 // The srcBuffer will at least be large enough | 
| 269 if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { | 311 if (stream->read(fSrcBuffer.get(), fAndMaskRowBytes) != fAndMaskRowBytes ) { | 
| 270 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); | 312 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); | 
| 271 return kIncompleteInput; | 313 return; | 
| 272 } | 314 } | 
| 273 | 315 | 
| 274 int row = this->getDstRow(y, dstInfo.height()); | 316 int row = this->getDstRow(y, dstInfo.height()); | 
| 275 | 317 | 
| 276 SkPMColor* dstRow = | 318 SkPMColor* dstRow = | 
| 277 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); | 319 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); | 
| 278 | 320 | 
| 279 for (int x = 0; x < width; x++) { | 321 for (int x = startX; x < this->getInfo().width(); x += sampleX) { | 
| 280 int quotient; | 322 int quotient; | 
| 281 int modulus; | 323 int modulus; | 
| 282 SkTDivMod(x, 8, "ient, &modulus); | 324 SkTDivMod(x, 8, "ient, &modulus); | 
| 283 uint32_t shift = 7 - modulus; | 325 uint32_t shift = 7 - modulus; | 
| 284 uint32_t alphaBit = | 326 uint32_t alphaBit = (fSrcBuffer.get()[quotient] >> shift) & 0x1; | 
| 285 (fSrcBuffer.get()[quotient] >> shift) & 0x1; | 327 dstRow[get_dst_coord(x, sampleX)] &= alphaBit - 1; | 
| 286 dstRow[x] &= alphaBit - 1; | |
| 287 } | 328 } | 
| 288 } | 329 } | 
| 289 return kSuccess; | |
| 290 } | 330 } | 
| 291 | 331 | 
| 292 uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType a lphaType) const { | 332 uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType a lphaType) const { | 
| 293 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 333 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 
| 294 if (colorPtr) { | 334 if (colorPtr) { | 
| 295 return get_color_table_fill_value(colorType, colorPtr, 0); | 335 return get_color_table_fill_value(colorType, colorPtr, 0); | 
| 296 } | 336 } | 
| 297 return INHERITED::onGetFillValue(colorType, alphaType); | 337 return INHERITED::onGetFillValue(colorType, alphaType); | 
| 298 } | 338 } | 
| OLD | NEW |