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

Side by Side Diff: dm/DMSrcSink.cpp

Issue 1982753002: Ensure that SkColorTable->fCount is set properly after decodes (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 7 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
« no previous file with comments | « no previous file | include/core/SkColorTable.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "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
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
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 = &subset; 535 opts.fSubset = &subset;
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 = &subset; 565 opts.fSubset = &subset;
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | include/core/SkColorTable.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698