| 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 |