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 "DMSrcSink.h" | 8 #include "DMSrcSink.h" |
9 #include "SkAndroidCodec.h" | 9 #include "SkAndroidCodec.h" |
10 #include "SkCodec.h" | 10 #include "SkCodec.h" |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 , fScale(scale) | 268 , fScale(scale) |
269 , fRunSerially(serial_from_path_name(path)) | 269 , fRunSerially(serial_from_path_name(path)) |
270 {} | 270 {} |
271 | 271 |
272 bool CodecSrc::veto(SinkFlags flags) const { | 272 bool CodecSrc::veto(SinkFlags flags) const { |
273 // Test to direct raster backends (8888 and 565). | 273 // Test to direct raster backends (8888 and 565). |
274 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDir
ect; | 274 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDir
ect; |
275 } | 275 } |
276 | 276 |
277 // Allows us to test decodes to non-native 8888. | 277 // Allows us to test decodes to non-native 8888. |
278 void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType)
{ | 278 static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstCol
orType) { |
279 if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) { | 279 if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) { |
280 return; | 280 return; |
281 } | 281 } |
282 | 282 |
283 for (int y = 0; y < bitmap.height(); y++) { | 283 for (int y = 0; y < bitmap.height(); y++) { |
284 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); | 284 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); |
285 SkOpts::RGBA_to_BGRA(row, row, bitmap.width()); | 285 SkOpts::RGBA_to_BGRA(row, row, bitmap.width()); |
286 } | 286 } |
287 } | 287 } |
288 | 288 |
289 // FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and s
kbug.com/3339. | 289 // FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and s
kbug.com/3339. |
290 // This allows us to still test unpremultiplied decodes. | 290 // This allows us to still test unpremultiplied decodes. |
291 void premultiply_if_necessary(SkBitmap& bitmap) { | 291 static void premultiply_if_necessary(SkBitmap& bitmap) { |
292 if (kUnpremul_SkAlphaType != bitmap.alphaType()) { | 292 if (kUnpremul_SkAlphaType != bitmap.alphaType()) { |
293 return; | 293 return; |
294 } | 294 } |
295 | 295 |
296 switch (bitmap.colorType()) { | 296 switch (bitmap.colorType()) { |
297 case kN32_SkColorType: | 297 case kN32_SkColorType: |
298 for (int y = 0; y < bitmap.height(); y++) { | 298 for (int y = 0; y < bitmap.height(); y++) { |
299 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); | 299 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); |
300 SkOpts::RGBA_to_rgbA(row, row, bitmap.width()); | 300 SkOpts::RGBA_to_rgbA(row, row, bitmap.width()); |
301 } | 301 } |
302 break; | 302 break; |
303 case kIndex_8_SkColorType: { | 303 case kIndex_8_SkColorType: { |
304 SkColorTable* colorTable = bitmap.getColorTable(); | 304 SkColorTable* colorTable = bitmap.getColorTable(); |
305 SkPMColor* colorPtr = const_cast<SkPMColor*>(colorTable->readColors(
)); | 305 SkPMColor* colorPtr = const_cast<SkPMColor*>(colorTable->readColors(
)); |
306 SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, colorTable->count()); | 306 SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, colorTable->count()); |
307 break; | 307 break; |
308 } | 308 } |
309 default: | 309 default: |
310 // No need to premultiply kGray or k565 outputs. | 310 // No need to premultiply kGray or k565 outputs. |
311 break; | 311 break; |
312 } | 312 } |
313 | 313 |
314 // In the kIndex_8 case, the canvas won't even try to draw unless we mark th
e | 314 // In the kIndex_8 case, the canvas won't even try to draw unless we mark th
e |
315 // bitmap as kPremul. | 315 // bitmap as kPremul. |
316 bitmap.setAlphaType(kPremul_SkAlphaType); | 316 bitmap.setAlphaType(kPremul_SkAlphaType); |
317 } | 317 } |
318 | 318 |
319 bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType, | 319 static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType
, |
320 CodecSrc::DstColorType dstColorType) { | 320 CodecSrc::DstColorType dstColorType) { |
321 switch (dstColorType) { | 321 switch (dstColorType) { |
322 case CodecSrc::kIndex8_Always_DstColorType: | 322 case CodecSrc::kIndex8_Always_DstColorType: |
323 if (kRGB_565_SkColorType == canvasColorType) { | 323 if (kRGB_565_SkColorType == canvasColorType) { |
324 return false; | 324 return false; |
325 } | 325 } |
326 *decodeInfo = decodeInfo->makeColorType(kIndex_8_SkColorType); | 326 *decodeInfo = decodeInfo->makeColorType(kIndex_8_SkColorType); |
327 break; | 327 break; |
328 case CodecSrc::kGrayscale_Always_DstColorType: | 328 case CodecSrc::kGrayscale_Always_DstColorType: |
329 if (kRGB_565_SkColorType == canvasColorType || | 329 if (kRGB_565_SkColorType == canvasColorType || |
330 kOpaque_SkAlphaType != decodeInfo->alphaType()) { | 330 kOpaque_SkAlphaType != decodeInfo->alphaType()) { |
(...skipping 16 matching lines...) Expand all Loading... |
347 kOpaque_SkAlphaType != decodeInfo->alphaType()) { | 347 kOpaque_SkAlphaType != decodeInfo->alphaType()) { |
348 return false; | 348 return false; |
349 } | 349 } |
350 *decodeInfo = decodeInfo->makeColorType(canvasColorType); | 350 *decodeInfo = decodeInfo->makeColorType(canvasColorType); |
351 break; | 351 break; |
352 } | 352 } |
353 | 353 |
354 return true; | 354 return true; |
355 } | 355 } |
356 | 356 |
| 357 static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixe
ls, size_t rowBytes, |
| 358 SkPMColor* colorPtr, int colorCount, CodecSrc::DstCol
orType dstColorType, |
| 359 SkScalar left = 0, SkScalar top = 0) { |
| 360 SkAutoTUnref<SkColorTable> colorTable(new SkColorTable(colorPtr, colorCount)
); |
| 361 SkBitmap bitmap; |
| 362 bitmap.installPixels(info, pixels, rowBytes, colorTable.get(), nullptr, null
ptr); |
| 363 premultiply_if_necessary(bitmap); |
| 364 swap_rb_if_necessary(bitmap, dstColorType); |
| 365 canvas->drawBitmap(bitmap, left, top); |
| 366 } |
| 367 |
357 Error CodecSrc::draw(SkCanvas* canvas) const { | 368 Error CodecSrc::draw(SkCanvas* canvas) const { |
358 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | 369 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
359 if (!encoded) { | 370 if (!encoded) { |
360 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 371 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); |
361 } | 372 } |
362 | 373 |
363 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); | 374 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); |
364 if (nullptr == codec.get()) { | 375 if (nullptr == codec.get()) { |
365 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); | 376 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); |
366 } | 377 } |
367 | 378 |
368 SkImageInfo decodeInfo = codec->getInfo().makeAlphaType(fDstAlphaType); | 379 SkImageInfo decodeInfo = codec->getInfo().makeAlphaType(fDstAlphaType); |
369 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColor
Type)) { | 380 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColor
Type)) { |
370 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); | 381 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); |
371 } | 382 } |
372 | 383 |
373 // Try to scale the image if it is desired | 384 // Try to scale the image if it is desired |
374 SkISize size = codec->getScaledDimensions(fScale); | 385 SkISize size = codec->getScaledDimensions(fScale); |
375 if (size == decodeInfo.dimensions() && 1.0f != fScale) { | 386 if (size == decodeInfo.dimensions() && 1.0f != fScale) { |
376 return Error::Nonfatal("Test without scaling is uninteresting."); | 387 return Error::Nonfatal("Test without scaling is uninteresting."); |
377 } | 388 } |
378 | 389 |
379 // Visually inspecting very small output images is not necessary. We will | 390 // Visually inspecting very small output images is not necessary. We will |
380 // cover these cases in unit testing. | 391 // cover these cases in unit testing. |
381 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { | 392 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { |
382 return Error::Nonfatal("Scaling very small images is uninteresting."); | 393 return Error::Nonfatal("Scaling very small images is uninteresting."); |
383 } | 394 } |
384 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); | 395 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); |
385 | 396 |
386 // Construct a color table for the decode if necessary | 397 const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); |
387 SkAutoTUnref<SkColorTable> colorTable(nullptr); | 398 const size_t rowBytes = size.width() * bpp; |
388 SkPMColor* colorPtr = nullptr; | 399 SkAutoMalloc pixels(decodeInfo.getSafeSize(rowBytes)); |
389 int* colorCountPtr = nullptr; | 400 SkPMColor colorPtr[256]; |
390 int maxColors = 256; | 401 int colorCount = 256; |
391 if (kIndex_8_SkColorType == decodeInfo.colorType()) { | |
392 SkPMColor colors[256]; | |
393 colorTable.reset(new SkColorTable(colors, maxColors)); | |
394 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | |
395 colorCountPtr = &maxColors; | |
396 } | |
397 | 402 |
398 SkBitmap bitmap; | |
399 SkPixelRefFactory* factory = nullptr; | |
400 SkMallocPixelRef::ZeroedPRFactory zeroFactory; | |
401 SkCodec::Options options; | 403 SkCodec::Options options; |
402 if (kCodecZeroInit_Mode == fMode) { | 404 if (kCodecZeroInit_Mode == fMode) { |
403 factory = &zeroFactory; | 405 memset(pixels.get(), 0, size.height() * rowBytes); |
404 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; | 406 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; |
405 } | 407 } |
406 | 408 |
407 SkImageInfo bitmapInfo = decodeInfo; | 409 SkImageInfo bitmapInfo = decodeInfo; |
408 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || | 410 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || |
409 kBGRA_8888_SkColorType == decodeInfo.colorType()) { | 411 kBGRA_8888_SkColorType == decodeInfo.colorType()) { |
410 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); | 412 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); |
411 } | 413 } |
412 if (!bitmap.tryAllocPixels(bitmapInfo, factory, colorTable.get())) { | |
413 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), | |
414 decodeInfo.width(), decodeInfo.height()); | |
415 } | |
416 | 414 |
417 switch (fMode) { | 415 switch (fMode) { |
418 case kCodecZeroInit_Mode: | 416 case kCodecZeroInit_Mode: |
419 case kCodec_Mode: { | 417 case kCodec_Mode: { |
420 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowB
ytes(), &options, | 418 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &option
s, |
421 colorPtr, colorCountPtr)) { | 419 colorPtr, &colorCount)) { |
422 case SkCodec::kSuccess: | 420 case SkCodec::kSuccess: |
423 // We consider incomplete to be valid, since we should still
decode what is | 421 // We consider incomplete to be valid, since we should still
decode what is |
424 // available. | 422 // available. |
425 case SkCodec::kIncompleteInput: | 423 case SkCodec::kIncompleteInput: |
426 break; | 424 break; |
427 default: | 425 default: |
428 // Everything else is considered a failure. | 426 // Everything else is considered a failure. |
429 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str(
)); | 427 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str(
)); |
430 } | 428 } |
431 premultiply_if_necessary(bitmap); | 429 |
432 swap_rb_if_necessary(bitmap, fDstColorType); | 430 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr,
colorCount, |
433 canvas->drawBitmap(bitmap, 0, 0); | 431 fDstColorType); |
434 break; | 432 break; |
435 } | 433 } |
436 case kScanline_Mode: { | 434 case kScanline_Mode: { |
437 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL
, colorPtr, | 435 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL
, colorPtr, |
438 colorCountPtr))
{ | 436 &colorCount)) { |
439 return "Could not start scanline decoder"; | 437 return "Could not start scanline decoder"; |
440 } | 438 } |
441 | 439 |
442 void* dst = bitmap.getAddr(0, 0); | 440 void* dst = pixels.get(); |
443 size_t rowBytes = bitmap.rowBytes(); | |
444 uint32_t height = decodeInfo.height(); | 441 uint32_t height = decodeInfo.height(); |
445 switch (codec->getScanlineOrder()) { | 442 switch (codec->getScanlineOrder()) { |
446 case SkCodec::kTopDown_SkScanlineOrder: | 443 case SkCodec::kTopDown_SkScanlineOrder: |
447 case SkCodec::kBottomUp_SkScanlineOrder: | 444 case SkCodec::kBottomUp_SkScanlineOrder: |
448 case SkCodec::kNone_SkScanlineOrder: | 445 case SkCodec::kNone_SkScanlineOrder: |
449 // We do not need to check the return value. On an incomple
te | 446 // We do not need to check the return value. On an incomple
te |
450 // image, memory will be filled with a default value. | 447 // image, memory will be filled with a default value. |
451 codec->getScanlines(dst, height, rowBytes); | 448 codec->getScanlines(dst, height, rowBytes); |
452 break; | 449 break; |
453 case SkCodec::kOutOfOrder_SkScanlineOrder: { | 450 case SkCodec::kOutOfOrder_SkScanlineOrder: { |
454 for (int y = 0; y < decodeInfo.height(); y++) { | 451 for (int y = 0; y < decodeInfo.height(); y++) { |
455 int dstY = codec->outputScanline(y); | 452 int dstY = codec->outputScanline(y); |
456 void* dstPtr = bitmap.getAddr(0, dstY); | 453 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * dstY); |
457 // We complete the loop, even if this call begins to fai
l | 454 // We complete the loop, even if this call begins to fai
l |
458 // due to an incomplete image. This ensures any uniniti
alized | 455 // due to an incomplete image. This ensures any uniniti
alized |
459 // memory will be filled with the proper value. | 456 // memory will be filled with the proper value. |
460 codec->getScanlines(dstPtr, 1, bitmap.rowBytes()); | 457 codec->getScanlines(dstPtr, 1, rowBytes); |
461 } | 458 } |
462 break; | 459 break; |
463 } | 460 } |
464 } | 461 } |
465 | 462 |
466 premultiply_if_necessary(bitmap); | 463 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCou
nt, fDstColorType); |
467 swap_rb_if_necessary(bitmap, fDstColorType); | |
468 canvas->drawBitmap(bitmap, 0, 0); | |
469 break; | 464 break; |
470 } | 465 } |
471 case kStripe_Mode: { | 466 case kStripe_Mode: { |
472 const int height = decodeInfo.height(); | 467 const int height = decodeInfo.height(); |
473 // This value is chosen arbitrarily. We exercise more cases by choo
sing a value that | 468 // This value is chosen arbitrarily. We exercise more cases by choo
sing a value that |
474 // does not align with image blocks. | 469 // does not align with image blocks. |
475 const int stripeHeight = 37; | 470 const int stripeHeight = 37; |
476 const int numStripes = (height + stripeHeight - 1) / stripeHeight; | 471 const int numStripes = (height + stripeHeight - 1) / stripeHeight; |
| 472 void* dst = pixels.get(); |
477 | 473 |
478 // Decode odd stripes | 474 // Decode odd stripes |
479 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL
, colorPtr, | 475 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, null
ptr, colorPtr, |
480 colorCountPtr))
{ | 476 &colorCount)) { |
481 return "Could not start scanline decoder"; | 477 return "Could not start scanline decoder"; |
482 } | 478 } |
483 | 479 |
484 // This mode was designed to test the new skip scanlines API in libj
peg-turbo. | 480 // This mode was designed to test the new skip scanlines API in libj
peg-turbo. |
485 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not
interesting | 481 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not
interesting |
486 // to run this test for image types that do not have this scanline o
rdering. | 482 // to run this test for image types that do not have this scanline o
rdering. |
487 // We only run this on Jpeg, which is always kTopDown. | 483 // We only run this on Jpeg, which is always kTopDown. |
488 SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrde
r()); | 484 SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrde
r()); |
489 | 485 |
490 for (int i = 0; i < numStripes; i += 2) { | 486 for (int i = 0; i < numStripes; i += 2) { |
491 // Skip a stripe | 487 // Skip a stripe |
492 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe
Height); | 488 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe
Height); |
493 codec->skipScanlines(linesToSkip); | 489 codec->skipScanlines(linesToSkip); |
494 | 490 |
495 // Read a stripe | 491 // Read a stripe |
496 const int startY = (i + 1) * stripeHeight; | 492 const int startY = (i + 1) * stripeHeight; |
497 const int linesToRead = SkTMin(stripeHeight, height - startY); | 493 const int linesToRead = SkTMin(stripeHeight, height - startY); |
498 if (linesToRead > 0) { | 494 if (linesToRead > 0) { |
499 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead,
bitmap.rowBytes()); | 495 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * start
Y), linesToRead, |
| 496 rowBytes); |
500 } | 497 } |
501 } | 498 } |
502 | 499 |
503 // Decode even stripes | 500 // Decode even stripes |
504 const SkCodec::Result startResult = codec->startScanlineDecode(decod
eInfo, nullptr, | 501 const SkCodec::Result startResult = codec->startScanlineDecode(decod
eInfo, nullptr, |
505 colorPtr, colorCountPtr); | 502 colorPtr, &colorCount); |
506 if (SkCodec::kSuccess != startResult) { | 503 if (SkCodec::kSuccess != startResult) { |
507 return "Failed to restart scanline decoder with same parameters.
"; | 504 return "Failed to restart scanline decoder with same parameters.
"; |
508 } | 505 } |
509 for (int i = 0; i < numStripes; i += 2) { | 506 for (int i = 0; i < numStripes; i += 2) { |
510 // Read a stripe | 507 // Read a stripe |
511 const int startY = i * stripeHeight; | 508 const int startY = i * stripeHeight; |
512 const int linesToRead = SkTMin(stripeHeight, height - startY); | 509 const int linesToRead = SkTMin(stripeHeight, height - startY); |
513 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitm
ap.rowBytes()); | 510 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY),
linesToRead, |
| 511 rowBytes); |
514 | 512 |
515 // Skip a stripe | 513 // Skip a stripe |
516 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) *
stripeHeight); | 514 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) *
stripeHeight); |
517 if (linesToSkip > 0) { | 515 if (linesToSkip > 0) { |
518 codec->skipScanlines(linesToSkip); | 516 codec->skipScanlines(linesToSkip); |
519 } | 517 } |
520 } | 518 } |
521 premultiply_if_necessary(bitmap); | 519 |
522 swap_rb_if_necessary(bitmap, fDstColorType); | 520 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCou
nt, fDstColorType); |
523 canvas->drawBitmap(bitmap, 0, 0); | |
524 break; | 521 break; |
525 } | 522 } |
526 case kCroppedScanline_Mode: { | 523 case kCroppedScanline_Mode: { |
527 const int width = decodeInfo.width(); | 524 const int width = decodeInfo.width(); |
528 const int height = decodeInfo.height(); | 525 const int height = decodeInfo.height(); |
529 // This value is chosen because, as we move across the image, it wil
l sometimes | 526 // This value is chosen because, as we move across the image, it wil
l sometimes |
530 // align with the jpeg block sizes and it will sometimes not. This
allows us | 527 // align with the jpeg block sizes and it will sometimes not. This
allows us |
531 // to test interestingly different code paths in the implementation. | 528 // to test interestingly different code paths in the implementation. |
532 const int tileSize = 36; | 529 const int tileSize = 36; |
533 | 530 |
534 SkCodec::Options opts; | 531 SkCodec::Options opts; |
535 SkIRect subset; | 532 SkIRect subset; |
536 for (int x = 0; x < width; x += tileSize) { | 533 for (int x = 0; x < width; x += tileSize) { |
537 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), he
ight); | 534 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), he
ight); |
538 opts.fSubset = ⊂ | 535 opts.fSubset = ⊂ |
539 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo,
&opts, | 536 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo,
&opts, |
540 colorPtr, colorCountPtr)) { | 537 colorPtr, &colorCount)) { |
541 return "Could not start scanline decoder."; | 538 return "Could not start scanline decoder."; |
542 } | 539 } |
543 | 540 |
544 codec->getScanlines(bitmap.getAddr(x, 0), height, bitmap.rowByte
s()); | 541 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), h
eight, rowBytes); |
545 } | 542 } |
546 | 543 |
547 premultiply_if_necessary(bitmap); | 544 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr,
colorCount, |
548 swap_rb_if_necessary(bitmap, fDstColorType); | 545 fDstColorType); |
549 canvas->drawBitmap(bitmap, 0, 0); | |
550 break; | 546 break; |
551 } | 547 } |
552 case kSubset_Mode: { | 548 case kSubset_Mode: { |
553 // Arbitrarily choose a divisor. | 549 // Arbitrarily choose a divisor. |
554 int divisor = 2; | 550 int divisor = 2; |
555 // Total width/height of the image. | 551 // Total width/height of the image. |
556 const int W = codec->getInfo().width(); | 552 const int W = codec->getInfo().width(); |
557 const int H = codec->getInfo().height(); | 553 const int H = codec->getInfo().height(); |
558 if (divisor > W || divisor > H) { | 554 if (divisor > W || divisor > H) { |
559 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divi
sor %d is too big " | 555 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divi
sor %d is too big " |
560 "for %s with dimensions (%
d x %d)", divisor, | 556 "for %s with dimensions (%
d x %d)", divisor, |
561 fPath.c_str(), W, H)); | 557 fPath.c_str(), W, H)); |
562 } | 558 } |
563 // subset dimensions | 559 // subset dimensions |
564 // SkWebpCodec, the only one that supports subsets, requires even to
p/left boundaries. | 560 // SkWebpCodec, the only one that supports subsets, requires even to
p/left boundaries. |
565 const int w = SkAlign2(W / divisor); | 561 const int w = SkAlign2(W / divisor); |
566 const int h = SkAlign2(H / divisor); | 562 const int h = SkAlign2(H / divisor); |
567 SkIRect subset; | 563 SkIRect subset; |
568 SkCodec::Options opts; | 564 SkCodec::Options opts; |
569 opts.fSubset = ⊂ | 565 opts.fSubset = ⊂ |
570 SkBitmap subsetBm; | 566 SkBitmap subsetBm; |
571 // We will reuse pixel memory from bitmap. | 567 // We will reuse pixel memory from bitmap. |
572 void* pixels = bitmap.getPixels(); | 568 void* dst = pixels.get(); |
573 // Keep track of left and top (for drawing subsetBm into canvas). We
could use | 569 // Keep track of left and top (for drawing subsetBm into canvas). We
could use |
574 // fScale * x and fScale * y, but we want integers such that the nex
t subset will start | 570 // fScale * x and fScale * y, but we want integers such that the nex
t subset will start |
575 // where the last one ended. So we'll add decodeInfo.width() and hei
ght(). | 571 // where the last one ended. So we'll add decodeInfo.width() and hei
ght(). |
576 int left = 0; | 572 int left = 0; |
577 for (int x = 0; x < W; x += w) { | 573 for (int x = 0; x < W; x += w) { |
578 int top = 0; | 574 int top = 0; |
579 for (int y = 0; y < H; y+= h) { | 575 for (int y = 0; y < H; y+= h) { |
580 // Do not make the subset go off the edge of the image. | 576 // Do not make the subset go off the edge of the image. |
581 const int preScaleW = SkTMin(w, W - x); | 577 const int preScaleW = SkTMin(w, W - x); |
582 const int preScaleH = SkTMin(h, H - y); | 578 const int preScaleH = SkTMin(h, H - y); |
583 subset.setXYWH(x, y, preScaleW, preScaleH); | 579 subset.setXYWH(x, y, preScaleW, preScaleH); |
584 // And scale | 580 // And scale |
585 // FIXME: Should we have a version of getScaledDimensions th
at takes a subset | 581 // FIXME: Should we have a version of getScaledDimensions th
at takes a subset |
586 // into account? | 582 // into account? |
587 const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW *
fScale)); | 583 const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW *
fScale)); |
588 const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH *
fScale)); | 584 const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH *
fScale)); |
589 decodeInfo = decodeInfo.makeWH(scaledW, scaledH); | 585 decodeInfo = decodeInfo.makeWH(scaledW, scaledH); |
590 SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, sc
aledH); | 586 SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, sc
aledH); |
591 size_t rowBytes = subsetBitmapInfo.minRowBytes(); | 587 size_t subsetRowBytes = subsetBitmapInfo.minRowBytes(); |
592 if (!subsetBm.installPixels(subsetBitmapInfo, pixels, rowByt
es, colorTable.get(), | 588 const SkCodec::Result result = codec->getPixels(decodeInfo,
dst, subsetRowBytes, |
593 nullptr, nullptr)) { | 589 &opts, colorPtr, &colorCount); |
594 return SkStringPrintf("could not install pixels for %s."
, fPath.c_str()); | |
595 } | |
596 const SkCodec::Result result = codec->getPixels(decodeInfo,
pixels, rowBytes, | |
597 &opts, colorPtr, colorCountPtr); | |
598 switch (result) { | 590 switch (result) { |
599 case SkCodec::kSuccess: | 591 case SkCodec::kSuccess: |
600 case SkCodec::kIncompleteInput: | 592 case SkCodec::kIncompleteInput: |
601 break; | 593 break; |
602 default: | 594 default: |
603 return SkStringPrintf("subset codec failed to decode
(%d, %d, %d, %d) " | 595 return SkStringPrintf("subset codec failed to decode
(%d, %d, %d, %d) " |
604 "from %s with dimensions (%d x
%d)\t error %d", | 596 "from %s with dimensions (%d x
%d)\t error %d", |
605 x, y, decodeInfo.width(), deco
deInfo.height(), | 597 x, y, decodeInfo.width(), deco
deInfo.height(), |
606 fPath.c_str(), W, H, result); | 598 fPath.c_str(), W, H, result); |
607 } | 599 } |
608 premultiply_if_necessary(subsetBm); | 600 draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes
, colorPtr, |
609 swap_rb_if_necessary(subsetBm, fDstColorType); | 601 colorCount, fDstColorType, SkIntToScalar(left
), |
610 canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToSca
lar(top)); | 602 SkIntToScalar(top)); |
| 603 |
611 // translate by the scaled height. | 604 // translate by the scaled height. |
612 top += decodeInfo.height(); | 605 top += decodeInfo.height(); |
613 } | 606 } |
614 // translate by the scaled width. | 607 // translate by the scaled width. |
615 left += decodeInfo.width(); | 608 left += decodeInfo.width(); |
616 } | 609 } |
617 return ""; | 610 return ""; |
618 } | 611 } |
619 default: | 612 default: |
620 SkASSERT(false); | 613 SkASSERT(false); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 // Scale the image if it is desired. | 667 // Scale the image if it is desired. |
675 SkISize size = codec->getSampledDimensions(fSampleSize); | 668 SkISize size = codec->getSampledDimensions(fSampleSize); |
676 | 669 |
677 // Visually inspecting very small output images is not necessary. We will | 670 // Visually inspecting very small output images is not necessary. We will |
678 // cover these cases in unit testing. | 671 // cover these cases in unit testing. |
679 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { | 672 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { |
680 return Error::Nonfatal("Scaling very small images is uninteresting."); | 673 return Error::Nonfatal("Scaling very small images is uninteresting."); |
681 } | 674 } |
682 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); | 675 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); |
683 | 676 |
684 // Construct a color table for the decode if necessary | 677 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); |
685 SkAutoTUnref<SkColorTable> colorTable(nullptr); | 678 size_t rowBytes = size.width() * bpp; |
686 SkPMColor* colorPtr = nullptr; | 679 SkAutoMalloc pixels(size.height() * rowBytes); |
687 int* colorCountPtr = nullptr; | 680 SkPMColor colorPtr[256]; |
688 int maxColors = 256; | 681 int colorCount = 256; |
689 if (kIndex_8_SkColorType == decodeInfo.colorType()) { | |
690 SkPMColor colors[256]; | |
691 colorTable.reset(new SkColorTable(colors, maxColors)); | |
692 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | |
693 colorCountPtr = &maxColors; | |
694 } | |
695 | 682 |
696 SkBitmap bitmap; | 683 SkBitmap bitmap; |
697 SkImageInfo bitmapInfo = decodeInfo; | 684 SkImageInfo bitmapInfo = decodeInfo; |
698 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || | 685 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || |
699 kBGRA_8888_SkColorType == decodeInfo.colorType()) { | 686 kBGRA_8888_SkColorType == decodeInfo.colorType()) { |
700 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); | 687 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); |
701 } | 688 } |
702 if (!bitmap.tryAllocPixels(bitmapInfo, nullptr, colorTable.get())) { | |
703 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), | |
704 decodeInfo.width(), decodeInfo.height()); | |
705 } | |
706 | 689 |
707 // Create options for the codec. | 690 // Create options for the codec. |
708 SkAndroidCodec::AndroidOptions options; | 691 SkAndroidCodec::AndroidOptions options; |
709 options.fColorPtr = colorPtr; | 692 options.fColorPtr = colorPtr; |
710 options.fColorCount = colorCountPtr; | 693 options.fColorCount = &colorCount; |
711 options.fSampleSize = fSampleSize; | 694 options.fSampleSize = fSampleSize; |
712 | 695 |
713 switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBy
tes(), &options)) { | 696 switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options
)) { |
714 case SkCodec::kSuccess: | 697 case SkCodec::kSuccess: |
715 case SkCodec::kIncompleteInput: | 698 case SkCodec::kIncompleteInput: |
716 break; | 699 break; |
717 default: | 700 default: |
718 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); | 701 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); |
719 } | 702 } |
720 premultiply_if_necessary(bitmap); | 703 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCo
unt, fDstColorType); |
721 swap_rb_if_necessary(bitmap, fDstColorType); | |
722 canvas->drawBitmap(bitmap, 0, 0); | |
723 return ""; | 704 return ""; |
724 } | 705 } |
725 | 706 |
726 SkISize AndroidCodecSrc::size() const { | 707 SkISize AndroidCodecSrc::size() const { |
727 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | 708 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
728 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); | 709 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); |
729 if (nullptr == codec) { | 710 if (nullptr == codec) { |
730 return SkISize::Make(0, 0); | 711 return SkISize::Make(0, 0); |
731 } | 712 } |
732 return codec->getSampledDimensions(fSampleSize); | 713 return codec->getSampledDimensions(fSampleSize); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
813 } | 794 } |
814 | 795 |
815 // Test various color and alpha types on CPU | 796 // Test various color and alpha types on CPU |
816 SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType); | 797 SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType); |
817 | 798 |
818 if (kGray_8_SkColorType == decodeInfo.colorType() && | 799 if (kGray_8_SkColorType == decodeInfo.colorType() && |
819 kOpaque_SkAlphaType != decodeInfo.alphaType()) { | 800 kOpaque_SkAlphaType != decodeInfo.alphaType()) { |
820 return Error::Nonfatal("Avoid requesting non-opaque kGray8 decodes."); | 801 return Error::Nonfatal("Avoid requesting non-opaque kGray8 decodes."); |
821 } | 802 } |
822 | 803 |
823 SkAutoTUnref<SkColorTable> colorTable(nullptr); | 804 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); |
824 SkPMColor* colorPtr = nullptr; | 805 size_t rowBytes = decodeInfo.width() * bpp; |
825 int* colorCountPtr = nullptr; | 806 SkAutoMalloc pixels(decodeInfo.height() * rowBytes); |
826 int maxColors = 256; | 807 SkPMColor colorPtr[256]; |
827 if (kIndex_8_SkColorType == decodeInfo.colorType()) { | 808 int colorCount = 256; |
828 SkPMColor colors[256]; | |
829 colorTable.reset(new SkColorTable(colors, maxColors)); | |
830 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | |
831 colorCountPtr = &maxColors; | |
832 } | |
833 | 809 |
834 SkBitmap bitmap; | 810 if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, colorPtr, &colorCoun
t)) { |
835 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { | |
836 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), | |
837 decodeInfo.width(), decodeInfo.height()); | |
838 } | |
839 | |
840 if (!gen->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), color
Ptr, | |
841 colorCountPtr)) | |
842 { | |
843 return SkStringPrintf("Image generator could not getPixels() for %s\n",
fPath.c_str()); | 811 return SkStringPrintf("Image generator could not getPixels() for %s\n",
fPath.c_str()); |
844 } | 812 } |
845 | 813 |
846 premultiply_if_necessary(bitmap); | 814 draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes, colorPtr, colorCo
unt, |
847 canvas->drawBitmap(bitmap, 0, 0); | 815 CodecSrc::kGetFromCanvas_DstColorType); |
848 return ""; | 816 return ""; |
849 } | 817 } |
850 | 818 |
851 SkISize ImageGenSrc::size() const { | 819 SkISize ImageGenSrc::size() const { |
852 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | 820 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
853 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); | 821 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); |
854 if (nullptr == codec) { | 822 if (nullptr == codec) { |
855 return SkISize::Make(0, 0); | 823 return SkISize::Make(0, 0); |
856 } | 824 } |
857 return codec->getInfo().dimensions(); | 825 return codec->getInfo().dimensions(); |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1494 skr.visit(i, drawsAsSingletonPictures); | 1462 skr.visit(i, drawsAsSingletonPictures); |
1495 } | 1463 } |
1496 sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture()); | 1464 sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture()); |
1497 | 1465 |
1498 canvas->drawPicture(macroPic); | 1466 canvas->drawPicture(macroPic); |
1499 return check_against_reference(bitmap, src, fSink); | 1467 return check_against_reference(bitmap, src, fSink); |
1500 }); | 1468 }); |
1501 } | 1469 } |
1502 | 1470 |
1503 } // namespace DM | 1471 } // namespace DM |
OLD | NEW |