Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: src/codec/SkCodec_libgif.cpp

Issue 1055743003: Swizzler changes Index8 and 565 (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Avoid setting a field to a local variable Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "SkCodec_libgif.h" 8 #include "SkCodec_libgif.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 break; 124 break;
125 } 125 }
126 } 126 }
127 127
128 // Use maximum unsigned int (surely an invalid index) to indicate that a val id 128 // Use maximum unsigned int (surely an invalid index) to indicate that a val id
129 // index was not found. 129 // index was not found.
130 return SK_MaxU32; 130 return SK_MaxU32;
131 } 131 }
132 132
133 /* 133 /*
134 * Read enough of the stream to initialize the SkGifCodec.
135 * Returns a bool representing success or failure.
136 * If it returned true, and codecOut was not NULL,
137 * it will be set to a new SkGifCodec.
138 */
139 bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut) {
140 // Read gif header, logical screen descriptor, and global color table
141 SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream));
142
143 if (NULL == gif) {
144 gif_error("DGifOpen failed.\n");
145 return false;
146 }
147
148 if (NULL != codecOut) {
149 // Get fields from header
150 const int32_t width = gif->SWidth;
151 const int32_t height = gif->SHeight;
152 if (width <= 0 || height <= 0) {
153 gif_error("Invalid dimensions.\n");
154 return false;
155 }
156
157 // Return the codec
158 // kIndex is the most natural color type for gifs, so we set this as
159 // the default.
160 // Many gifs specify a color table index for transparent pixels. Every
161 // other pixel is guaranteed to be opaque. Despite this, because of the
162 // possiblity of transparent pixels, we cannot assume that the image is
163 // opaque. We have the option to set the alpha type as kPremul or
164 // kUnpremul. Both are valid since the alpha component will always be
165 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
166 // kPremul because we support kPremul, and it is more efficient to
167 // use kPremul directly even when kUnpremul is supported.
168 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
169 kIndex_8_SkColorType, kPremul_SkAlphaType);
170 *codecOut = SkNEW_ARGS(SkGifCodec, (imageInfo, stream, gif.detach()));
171 }
172 return true;
173 }
174
175 /*
134 * Assumes IsGif was called and returned true 176 * Assumes IsGif was called and returned true
135 * Creates a gif decoder 177 * Creates a gif decoder
136 * Reads enough of the stream to determine the image format 178 * Reads enough of the stream to determine the image format
137 */ 179 */
138 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { 180 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
139 // Read gif header, logical screen descriptor, and global color table 181 SkCodec* codec = NULL;
140 SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream)); 182 if (ReadHeader(stream, &codec)) {
141 183 return codec;
142 if (NULL == gif) {
143 gif_error("DGifOpen failed.\n");
144 return NULL;
145 } 184 }
146 185 return NULL;
147 // Get fields from header
148 const int32_t width = gif->SWidth;
149 const int32_t height = gif->SHeight;
150 if (width <= 0 || height <= 0) {
151 gif_error("Invalid dimensions.\n");
152 return NULL;
153 }
154
155 // Return the codec
156 // kIndex is the most natural color type for gifs, so we set this as
157 // the default.
158 // Many gifs specify a color table index for transparent pixels. Every
159 // other pixel is guaranteed to be opaque. Despite this, because of the
160 // possiblity of transparent pixels, we cannot assume that the image is
161 // opaque. We have the option to set the alpha type as kPremul or
162 // kUnpremul. Both are valid since the alpha component will always be
163 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
164 // kPremul because we support kPremul, and it is more efficient to
165 // use kPremul directly even when kUnpremul is supported.
166 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
167 kIndex_8_SkColorType, kPremul_SkAlphaType);
168 return SkNEW_ARGS(SkGifCodec, (imageInfo, stream, gif.detach()));
169 } 186 }
170 187
171 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, 188 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream,
172 GifFileType* gif) 189 GifFileType* gif)
173 : INHERITED(srcInfo, stream) 190 : INHERITED(srcInfo, stream)
174 , fGif(gif) 191 , fGif(gif)
175 {} 192 {}
176 193
177 /* 194 /*
178 * Checks if the conversion between the input image and the requested output 195 * Checks if the conversion between the input image and the requested output
179 * image has been implemented 196 * image has been implemented
180 */ 197 */
181 static bool conversion_possible(const SkImageInfo& dst, 198 static bool conversion_possible(const SkImageInfo& dst,
182 const SkImageInfo& src) { 199 const SkImageInfo& src) {
183 // Ensure that the profile type is unchanged 200 // Ensure that the profile type is unchanged
184 if (dst.profileType() != src.profileType()) { 201 if (dst.profileType() != src.profileType()) {
185 return false; 202 return false;
186 } 203 }
187 204
188 // Check for supported color and alpha types 205 // Check for supported color and alpha types
189 switch (dst.colorType()) { 206 switch (dst.colorType()) {
190 case kN32_SkColorType: 207 case kN32_SkColorType:
191 return kPremul_SkAlphaType == dst.alphaType() || 208 return kPremul_SkAlphaType == dst.alphaType() ||
192 kUnpremul_SkAlphaType == dst.alphaType(); 209 kUnpremul_SkAlphaType == dst.alphaType();
210 case kIndex_8_SkColorType:
211 return kPremul_SkAlphaType == dst.alphaType() ||
212 kUnpremul_SkAlphaType == dst.alphaType();
193 default: 213 default:
194 return false; 214 return false;
195 } 215 }
196 } 216 }
197 217
198 /* 218 /*
199 * Initiates the gif decode 219 * Initiates the gif decode
200 */ 220 */
201 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, 221 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
202 void* dst, size_t dstRowBytes, 222 void* dst, size_t dstRowBytes,
203 const Options& opts, SkPMColor*, int*) { 223 const Options& opts,
224 SkPMColor* inputColorPtr,
225 int* inputColorCount) {
226 // Rewind if necessary
227 SkCodec::RewindState rewindState = this->rewindIfNeeded();
228 if (rewindState == kCouldNotRewind_RewindState) {
229 return kCouldNotRewind;
230 } else if (rewindState == kRewound_RewindState) {
231 if (!ReadHeader(this->stream(), NULL)) {
232 return kCouldNotRewind;
233 }
234 }
235
204 // Check for valid input parameters 236 // Check for valid input parameters
205 if (!this->rewindIfNeeded()) {
206 return kCouldNotRewind;
207 }
208 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 237 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
209 return gif_error("Scaling not supported.\n", kInvalidScale); 238 return gif_error("Scaling not supported.\n", kInvalidScale);
210 } 239 }
211 if (!conversion_possible(dstInfo, this->getInfo())) { 240 if (!conversion_possible(dstInfo, this->getInfo())) {
212 return gif_error("Cannot convert input type to output type.\n", 241 return gif_error("Cannot convert input type to output type.\n",
213 kInvalidConversion); 242 kInvalidConversion);
214 } 243 }
215 244
216 // Use this as a container to hold information about any gif extension 245 // Use this as a container to hold information about any gif extension
217 // blocks. This generally stores transparency and animation instructions. 246 // blocks. This generally stores transparency and animation instructions.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 innerHeight = height; 306 innerHeight = height;
278 imageTop = 0; 307 imageTop = 0;
279 } else if (imageTop + innerHeight > height) { 308 } else if (imageTop + innerHeight > height) {
280 gif_warning("Shifting inner image up to fit.\n"); 309 gif_warning("Shifting inner image up to fit.\n");
281 imageTop = height - innerHeight; 310 imageTop = height - innerHeight;
282 } else if (imageTop < 0) { 311 } else if (imageTop < 0) {
283 gif_warning("Shifting image down to fit\n"); 312 gif_warning("Shifting image down to fit\n");
284 imageTop = 0; 313 imageTop = 0;
285 } 314 }
286 315
316 // Create a color table to store colors the giflib colorMap
317 SkPMColor alternateColorPtr[256];
318 SkPMColor* colorTable;
319 SkColorType dstColorType = dstInfo.colorType();
320 if (kIndex_8_SkColorType == dstColorType) {
321 SkASSERT(NULL != inputColorPtr);
322 SkASSERT(NULL != inputColorCount);
323 SkASSERT(256 == *inputColorCount);
324 colorTable = inputColorPtr;
325 } else {
326 colorTable = alternateColorPtr;
327 }
328
287 // Set up the color table 329 // Set up the color table
288 uint32_t colorCount = 0; 330 uint32_t colorCount = 0;
289 // Allocate maximum storage to deal with invalid indices safely 331 // Allocate maximum storage to deal with invalid indices safely
290 const uint32_t maxColors = 256; 332 const uint32_t maxColors = 256;
291 SkPMColor colorTable[maxColors];
292 ColorMapObject* colorMap = fGif->Image.ColorMap; 333 ColorMapObject* colorMap = fGif->Image.ColorMap;
293 // If there is no local color table, use the global color table 334 // If there is no local color table, use the global color table
294 if (NULL == colorMap) { 335 if (NULL == colorMap) {
295 colorMap = fGif->SColorMap; 336 colorMap = fGif->SColorMap;
296 } 337 }
297 if (NULL != colorMap) { 338 if (NULL != colorMap) {
298 colorCount = colorMap->ColorCount; 339 colorCount = colorMap->ColorCount;
299 SkASSERT(colorCount == 340 SkASSERT(colorCount ==
300 (unsigned) (1 << (colorMap->BitsPerPixel))); 341 (unsigned) (1 << (colorMap->BitsPerPixel)));
301 SkASSERT(colorCount <= 256); 342 SkASSERT(colorCount <= 256);
302 for (uint32_t i = 0; i < colorCount; i++) { 343 for (uint32_t i = 0; i < colorCount; i++) {
303 colorTable[i] = SkPackARGB32(0xFF, 344 colorTable[i] = SkPackARGB32(0xFF,
304 colorMap->Colors[i].Red, 345 colorMap->Colors[i].Red,
305 colorMap->Colors[i].Green, 346 colorMap->Colors[i].Green,
306 colorMap->Colors[i].Blue); 347 colorMap->Colors[i].Blue);
307 } 348 }
308 } 349 }
309 350
310 // This is used to fill unspecified pixels in the image data. 351 // This is used to fill unspecified pixels in the image data.
311 uint32_t fillIndex = fGif->SBackGroundColor; 352 uint32_t fillIndex = fGif->SBackGroundColor;
312 bool fillBackground = true;
313 ZeroInitialized zeroInit = opts.fZeroInitialized; 353 ZeroInitialized zeroInit = opts.fZeroInitialized;
314 354
315 // Gifs have the option to specify the color at a single 355 // Gifs have the option to specify the color at a single
316 // index of the color table as transparent. 356 // index of the color table as transparent.
317 { 357 {
318 // Get the transparent index. If the return value of this 358 // Get the transparent index. If the return value of this
319 // function is greater than the colorCount, we know that 359 // function is greater than the colorCount, we know that
320 // there is no valid transparent color in the color table. 360 // there is no valid transparent color in the color table.
321 // This occurs if there is no graphics control extension or 361 // This occurs if there is no graphics control extension or
322 // if the index specified by the graphics control extension 362 // if the index specified by the graphics control extension
323 // is out of range. 363 // is out of range.
324 uint32_t transIndex = find_trans_index(saveExt); 364 uint32_t transIndex = find_trans_index(saveExt);
325 365
326 // If the background is already zeroed and we have a valid
327 // transparent index, we do not need to fill the background.
328 if (transIndex < colorCount) { 366 if (transIndex < colorCount) {
329 colorTable[transIndex] = SK_ColorTRANSPARENT; 367 colorTable[transIndex] = SK_ColorTRANSPARENT;
330 // If there is a transparent index, we also use this as 368 // If there is a transparent index, we also use this as
331 // the fill index. 369 // the fill index.
332 fillIndex = transIndex; 370 fillIndex = transIndex;
333 fillBackground = (kYes_ZeroInitialized != zeroInit);
334 } else if (fillIndex >= colorCount) { 371 } else if (fillIndex >= colorCount) {
335 // If the fill index is invalid, we default to 0. This 372 // If the fill index is invalid, we default to 0. This
336 // behavior is unspecified but matches SkImageDecoder. 373 // behavior is unspecified but matches SkImageDecoder.
337 fillIndex = 0; 374 fillIndex = 0;
338 } 375 }
339 } 376 }
340 377
378 // Check if we can skip filling the background of the image. We
379 // may be able to if the memory is zero initialized.
380 bool skipBackground =
381 (kN32_SkColorType == dstColorType && colorTable[fillInde x] == 0) ||
382 (kIndex_8_SkColorType == dstColorType && fillIndex == 0) ;
scroggo 2015/04/06 14:55:11 Don't we want to also check zeroInit?
msarett 2015/04/06 18:10:55 Yes of course, thanks for catching this.
383
384
341 // Fill in the color table for indices greater than color count. 385 // Fill in the color table for indices greater than color count.
342 // This allows for predictable, safe behavior. 386 // This allows for predictable, safe behavior.
343 for (uint32_t i = colorCount; i < maxColors; i++) { 387 for (uint32_t i = colorCount; i < maxColors; i++) {
344 colorTable[i] = colorTable[fillIndex]; 388 colorTable[i] = colorTable[fillIndex];
345 } 389 }
346 390
347 // Check if image is only a subset of the image frame 391 // Check if image is only a subset of the image frame
348 SkAutoTDelete<SkSwizzler> swizzler(NULL); 392 SkAutoTDelete<SkSwizzler> swizzler(NULL);
349 if (innerWidth < width || innerHeight < height) { 393 if (innerWidth < width || innerHeight < height) {
350 394
351 // Modify the destination info 395 // Modify the destination info
352 const SkImageInfo subsetDstInfo = 396 const SkImageInfo subsetDstInfo =
353 dstInfo.makeWH(innerWidth, innerHeight); 397 dstInfo.makeWH(innerWidth, innerHeight);
354 398
355 // Fill the destination with the fill color 399 // Fill the destination with the fill color
356 // FIXME: This may not be the behavior that we want for 400 // FIXME: This may not be the behavior that we want for
357 // animated gifs where we draw on top of the 401 // animated gifs where we draw on top of the
358 // previous frame. 402 // previous frame.
359 SkColorType dstColorType = dstInfo.colorType(); 403 if (!skipBackground) {
360 if (fillBackground) { 404 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, 0, fillIndex , colorTable);
361 switch (dstColorType) {
362 case kN32_SkColorType:
363 sk_memset32((SkPMColor*) dst,
364 colorTable[fillIndex],
365 ((int) dstRowBytes) * height
366 / sizeof(SkPMColor));
367 break;
368 default:
369 SkASSERT(false);
370 break;
371 }
372 } 405 }
373 406
374 // Modify the dst pointer 407 // Modify the dst pointer
375 const int32_t dstBytesPerPixel = 408 const int32_t dstBytesPerPixel =
376 SkColorTypeBytesPerPixel(dstColorType); 409 SkColorTypeBytesPerPixel(dstColorType);
377 void* subsetDst = SkTAddOffset<void*>(dst, 410 void* subsetDst = SkTAddOffset<void*>(dst,
378 dstRowBytes * imageTop + 411 dstRowBytes * imageTop +
379 dstBytesPerPixel * imageLeft); 412 dstBytesPerPixel * imageLeft);
380 413
381 // Create the subset swizzler 414 // Create the subset swizzler
(...skipping 14 matching lines...) Expand all
396 // Check the interlace flag and iterate over rows of the input 429 // Check the interlace flag and iterate over rows of the input
397 if (fGif->Image.Interlace) { 430 if (fGif->Image.Interlace) {
398 // In interlace mode, the rows of input are rearranged in 431 // In interlace mode, the rows of input are rearranged in
399 // the output image. We use an iterator to take care of 432 // the output image. We use an iterator to take care of
400 // the rearranging. 433 // the rearranging.
401 SkGifInterlaceIter iter(innerHeight); 434 SkGifInterlaceIter iter(innerHeight);
402 for (int32_t y = 0; y < innerHeight; y++) { 435 for (int32_t y = 0; y < innerHeight; y++) {
403 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), 436 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
404 innerWidth)) { 437 innerWidth)) {
405 // Recover from error by filling remainder of image 438 // Recover from error by filling remainder of image
406 if (fillBackground) { 439 if (!skipBackground) {
407 memset(buffer.get(), fillIndex, innerWidth); 440 memset(buffer.get(), fillIndex, innerWidth);
408 for (; y < innerHeight; y++) { 441 for (; y < innerHeight; y++) {
409 swizzler->next(buffer.get(), iter.nextY()); 442 swizzler->next(buffer.get(), iter.nextY());
410 } 443 }
411 } 444 }
412 return gif_error(SkStringPrintf( 445 return gif_error(SkStringPrintf(
413 "Could not decode line %d of %d.\n", 446 "Could not decode line %d of %d.\n",
414 y, height - 1).c_str(), kIncompleteInput); 447 y, height - 1).c_str(), kIncompleteInput);
415 } 448 }
416 swizzler->next(buffer.get(), iter.nextY()); 449 swizzler->next(buffer.get(), iter.nextY());
417 } 450 }
418 } else { 451 } else {
419 // Standard mode 452 // Standard mode
420 for (int32_t y = 0; y < innerHeight; y++) { 453 for (int32_t y = 0; y < innerHeight; y++) {
421 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), 454 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
422 innerWidth)) { 455 innerWidth)) {
423 if (fillBackground) { 456 if (!skipBackground) {
424 SkPMColor* dstPtr = (SkPMColor*) SkTAddOffset 457 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, y, f illIndex,
425 <void*>(dst, y * dstRowBytes); 458 colorTable);
426 sk_memset32(dstPtr, colorTable[fillIndex],
427 (height - y) * ((int) dstRowBytes)
428 / sizeof(SkPMColor));
429 } 459 }
430 return gif_error(SkStringPrintf( 460 return gif_error(SkStringPrintf(
431 "Could not decode line %d of %d.\n", 461 "Could not decode line %d of %d.\n",
432 y, height - 1).c_str(), kIncompleteInput); 462 y, height - 1).c_str(), kIncompleteInput);
433 } 463 }
434 swizzler->next(buffer.get()); 464 swizzler->next(buffer.get());
435 } 465 }
436 } 466 }
437 467
438 // FIXME: Gif files may have multiple images stored in a single 468 // FIXME: Gif files may have multiple images stored in a single
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 // giflib returns an error code if the record type is not known. 538 // giflib returns an error code if the record type is not known.
509 // We should catch this error immediately. 539 // We should catch this error immediately.
510 SkASSERT(false); 540 SkASSERT(false);
511 break; 541 break;
512 } 542 }
513 } while (TERMINATE_RECORD_TYPE != recordType); 543 } while (TERMINATE_RECORD_TYPE != recordType);
514 544
515 return gif_error("Could not find any images to decode in gif file.\n", 545 return gif_error("Could not find any images to decode in gif file.\n",
516 kInvalidInput); 546 kInvalidInput);
517 } 547 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698