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" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
53 | 53 |
54 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol orCount); | 54 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol orCount); |
55 if (kSuccess != result) { | 55 if (kSuccess != result) { |
56 return result; | 56 return result; |
57 } | 57 } |
58 int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); | 58 int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); |
59 if (rows != dstInfo.height()) { | 59 if (rows != dstInfo.height()) { |
60 *rowsDecoded = rows; | 60 *rowsDecoded = rows; |
61 return kIncompleteInput; | 61 return kIncompleteInput; |
62 } | 62 } |
63 if (fInIco) { | |
64 return this->decodeIcoMask(dstInfo, dst, dstRowBytes); | |
65 } | |
66 return kSuccess; | 63 return kSuccess; |
67 } | 64 } |
68 | 65 |
69 /* | 66 /* |
70 * Process the color table for the bmp input | 67 * Process the color table for the bmp input |
71 */ | 68 */ |
72 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors ) { | 69 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors ) { |
73 // Allocate memory for color table | 70 // Allocate memory for color table |
74 uint32_t colorBytes = 0; | 71 uint32_t colorBytes = 0; |
75 SkPMColor colorTable[256]; | 72 SkPMColor colorTable[256]; |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 if (!this->initializeSwizzler(dstInfo, options)) { | 217 if (!this->initializeSwizzler(dstInfo, options)) { |
221 SkCodecPrintf("Error: cannot initialize swizzler.\n"); | 218 SkCodecPrintf("Error: cannot initialize swizzler.\n"); |
222 return SkCodec::kInvalidConversion; | 219 return SkCodec::kInvalidConversion; |
223 } | 220 } |
224 return SkCodec::kSuccess; | 221 return SkCodec::kSuccess; |
225 } | 222 } |
226 | 223 |
227 /* | 224 /* |
228 * Performs the bitmap decoding for standard input format | 225 * Performs the bitmap decoding for standard input format |
229 */ | 226 */ |
230 int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, | 227 int SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, |
231 void* dst, size_t dstRowBytes, | 228 const Options& opts) { |
232 const Options& opts) { | |
233 // Iterate over rows of the image | 229 // Iterate over rows of the image |
234 const int height = dstInfo.height(); | 230 const int height = dstInfo.height(); |
235 for (int y = 0; y < height; y++) { | 231 for (int y = 0; y < height; y++) { |
236 // Read a row of the input | 232 // Read a row of the input |
237 if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes ) { | 233 if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes ) { |
238 SkCodecPrintf("Warning: incomplete input stream.\n"); | 234 SkCodecPrintf("Warning: incomplete input stream.\n"); |
239 return y; | 235 return y; |
240 } | 236 } |
241 | 237 |
242 // Decode the row in destination format | 238 // Decode the row in destination format |
243 uint32_t row = this->getDstRow(y, dstInfo.height()); | 239 uint32_t row = this->getDstRow(y, dstInfo.height()); |
244 | 240 |
245 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); | 241 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); |
246 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 242 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
247 } | 243 } |
248 | 244 |
249 // Finished decoding the entire image | 245 if (fInIco) { |
246 const int startScanline = this->currScanline(); | |
247 const size_t andMaskRowBytes = SkAlign4(compute_row_bytes(this->getInfo( ).width(), 1)); | |
248 if (startScanline < 0) { | |
249 // We are not performing a scanline decode. | |
250 // Just decode the entire ICO mask and return. | |
251 decodeIcoMask(dstInfo, dst, dstRowBytes, andMaskRowBytes); | |
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. We also must be able to return | |
258 // the stream to its original position in order to decode the | |
259 // next scanline on a subsequent request. | |
260 // We will do this by taking advantage of the fact that | |
261 // SkIcoCodec always uses a SkMemoryStream as its underlying | |
262 // representation of the stream. | |
263 SkMemoryStream* stream = (SkMemoryStream*) this->stream(); | |
264 const size_t startPosition = stream->getPosition(); | |
265 | |
266 const int remainingScanlines = this->getInfo().height() - startScanline - height; | |
267 const size_t bytesToSkip = remainingScanlines * fSrcRowBytes + | |
268 startScanline * andMaskRowBytes; | |
269 if (bytesToSkip != stream->skip(bytesToSkip)) { | |
270 // FIXME: How can we indicate that this decode was actually incomple te? | |
271 stream->seek(startPosition); | |
272 return height; | |
273 } | |
274 // FIXME: If decodeIcoMask does not succeed, is there a way that we can | |
275 // indicate the decode was incomplete? | |
276 decodeIcoMask(dstInfo, dst, dstRowBytes, andMaskRowBytes); | |
277 stream->seek(startPosition); | |
278 } | |
279 | |
250 return height; | 280 return height; |
251 } | 281 } |
252 | 282 |
253 // TODO (msarett): This function will need to be modified in order to perform ro w by row decodes | 283 void SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, |
254 // when the Ico scanline decoder is implemented. | 284 void* dst, size_t dstRowBytes, size_t srcRowBytes) { |
255 SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo, | |
256 void* dst, size_t dstRowBytes) { | |
257 // BMP in ICO have transparency, so this cannot be 565, and this mask | 285 // 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 | 286 // prevents us from using kIndex8. The below code depends on the output |
259 // being an SkPMColor. | 287 // being an SkPMColor. |
260 SkASSERT(dstInfo.colorType() == kN32_SkColorType); | 288 SkASSERT(dstInfo.colorType() == kN32_SkColorType); |
261 | 289 |
262 // The AND mask is always 1 bit per pixel | |
263 const int width = this->getInfo().width(); | |
264 const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1)); | |
265 | |
266 SkPMColor* dstPtr = (SkPMColor*) dst; | 290 SkPMColor* dstPtr = (SkPMColor*) dst; |
267 for (int y = 0; y < dstInfo.height(); y++) { | 291 for (int y = 0; y < dstInfo.height(); y++) { |
268 // The srcBuffer will at least be large enough | 292 // The srcBuffer will at least be large enough |
269 if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { | 293 if (this->stream()->read(fSrcBuffer.get(), srcRowBytes) != srcRowBytes) { |
270 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); | 294 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); |
271 return kIncompleteInput; | 295 return; |
272 } | 296 } |
273 | 297 |
274 int row = this->getDstRow(y, dstInfo.height()); | 298 int row = this->getDstRow(y, dstInfo.height()); |
275 | 299 |
276 SkPMColor* dstRow = | 300 SkPMColor* dstRow = |
277 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); | 301 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); |
278 | 302 |
279 for (int x = 0; x < width; x++) { | 303 for (int x = 0; x < this->getInfo().width(); x++) { |
280 int quotient; | 304 int quotient; |
281 int modulus; | 305 int modulus; |
282 SkTDivMod(x, 8, "ient, &modulus); | 306 SkTDivMod(x, 8, "ient, &modulus); |
283 uint32_t shift = 7 - modulus; | 307 uint32_t shift = 7 - modulus; |
284 uint32_t alphaBit = | 308 uint32_t alphaBit = |
285 (fSrcBuffer.get()[quotient] >> shift) & 0x1; | 309 (fSrcBuffer.get()[quotient] >> shift) & 0x1; |
286 dstRow[x] &= alphaBit - 1; | 310 dstRow[x] &= alphaBit - 1; |
msarett
2015/11/24 22:43:35
This is currently broken. We either need to know
| |
287 } | 311 } |
288 } | 312 } |
289 return kSuccess; | |
290 } | 313 } |
291 | 314 |
292 uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType a lphaType) const { | 315 uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType, SkAlphaType a lphaType) const { |
293 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 316 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
294 if (colorPtr) { | 317 if (colorPtr) { |
295 return get_color_table_fill_value(colorType, colorPtr, 0); | 318 return get_color_table_fill_value(colorType, colorPtr, 0); |
296 } | 319 } |
297 return INHERITED::onGetFillValue(colorType, alphaType); | 320 return INHERITED::onGetFillValue(colorType, alphaType); |
298 } | 321 } |
OLD | NEW |