1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc. 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 86843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com#include "gm_expectations.h" 9af459795e393dabd8ea02afade5609935c0d9509reed@android.com#include "SkBitmap.h" 1039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com#include "SkColorPriv.h" 11b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com#include "SkCommandLineFlags.h" 1239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com#include "SkData.h" 137def5e1630d47cdbfa4b58a9c86bc060693c4d79scroggo@google.com#include "SkForceLinking.h" 14af459795e393dabd8ea02afade5609935c0d9509reed@android.com#include "SkGraphics.h" 15af459795e393dabd8ea02afade5609935c0d9509reed@android.com#include "SkImageDecoder.h" 16af459795e393dabd8ea02afade5609935c0d9509reed@android.com#include "SkImageEncoder.h" 17b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com#include "SkOSFile.h" 187e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com#include "SkRandom.h" 19af459795e393dabd8ea02afade5609935c0d9509reed@android.com#include "SkStream.h" 20b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com#include "SkTArray.h" 21af459795e393dabd8ea02afade5609935c0d9509reed@android.com#include "SkTemplates.h" 22af459795e393dabd8ea02afade5609935c0d9509reed@android.com 237def5e1630d47cdbfa4b58a9c86bc060693c4d79scroggo@google.com__SK_FORCE_IMAGE_DECODER_LINKING; 247def5e1630d47cdbfa4b58a9c86bc060693c4d79scroggo@google.com 256d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.comDEFINE_string(config, "None", "Preferred config to decode into. [None|8888|565|A8]"); 266843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.comDEFINE_string(createExpectationsPath, "", "Path to write JSON expectations."); 27cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.comDEFINE_string(mismatchPath, "", "Folder to write mismatched images to."); 28b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.comDEFINE_string2(readPath, r, "", "Folder(s) and files to decode images. Required."); 296843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.comDEFINE_string(readExpectationsPath, "", "Path to read JSON expectations from."); 3039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comDEFINE_bool(reencode, true, "Reencode the images to test encoding."); 31dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.orgDEFINE_int32(sampleSize, 1, "Set the sampleSize for decoding."); 32dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.orgDEFINE_bool(skip, false, "Skip writing zeroes."); 337e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.comDEFINE_bool(testSubsetDecoding, true, "Test decoding subsets of images."); 345187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.comDEFINE_bool(writeChecksumBasedFilenames, false, "When writing out actual images, use checksum-" 355187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com "based filenames, as rebaseline.py will use when downloading them from Google Storage"); 36cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.comDEFINE_string2(writePath, w, "", "Write rendered images into this directory."); 37b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 3839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstruct Format { 3939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkImageEncoder::Type fType; 4039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkImageDecoder::Format fFormat; 4139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com const char* fSuffix; 4239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}; 43b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 4439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic const Format gFormats[] = { 4539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com { SkImageEncoder::kBMP_Type, SkImageDecoder::kBMP_Format, ".bmp" }, 4639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com { SkImageEncoder::kGIF_Type, SkImageDecoder::kGIF_Format, ".gif" }, 4739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com { SkImageEncoder::kICO_Type, SkImageDecoder::kICO_Format, ".ico" }, 4839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com { SkImageEncoder::kJPEG_Type, SkImageDecoder::kJPEG_Format, ".jpg" }, 4939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com { SkImageEncoder::kPNG_Type, SkImageDecoder::kPNG_Format, ".png" }, 5039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com { SkImageEncoder::kWBMP_Type, SkImageDecoder::kWBMP_Format, ".wbmp" }, 5139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com { SkImageEncoder::kWEBP_Type, SkImageDecoder::kWEBP_Format, ".webp" } 5239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}; 53af459795e393dabd8ea02afade5609935c0d9509reed@android.com 5439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkImageEncoder::Type format_to_type(SkImageDecoder::Format format) { 5539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) { 5639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (gFormats[i].fFormat == format) { 5739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return gFormats[i].fType; 5839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 59af459795e393dabd8ea02afade5609935c0d9509reed@android.com } 6039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageEncoder::kUnknown_Type; 6139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 62af459795e393dabd8ea02afade5609935c0d9509reed@android.com 6339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic const char* suffix_for_type(SkImageEncoder::Type type) { 6439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) { 6539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (gFormats[i].fType == type) { 6639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return gFormats[i].fSuffix; 6739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 68af459795e393dabd8ea02afade5609935c0d9509reed@android.com } 6939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return ""; 70af459795e393dabd8ea02afade5609935c0d9509reed@android.com} 71af459795e393dabd8ea02afade5609935c0d9509reed@android.com 7239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkImageDecoder::Format guess_format_from_suffix(const char suffix[]) { 7339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) { 7439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (strcmp(suffix, gFormats[i].fSuffix) == 0) { 7539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return gFormats[i].fFormat; 7639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 7739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 7839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return SkImageDecoder::kUnknown_Format; 7939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 80af459795e393dabd8ea02afade5609935c0d9509reed@android.com 8139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic void make_outname(SkString* dst, const char outDir[], const char src[], 8239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com const char suffix[]) { 83ccd7afb6fb2df9774e57fb4d7f62f9504cabf03escroggo@google.com SkString basename = SkOSPath::SkBasename(src); 84ccd7afb6fb2df9774e57fb4d7f62f9504cabf03escroggo@google.com dst->set(SkOSPath::SkPathJoin(outDir, basename.c_str())); 855187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com dst->append(suffix); 8639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 8739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 8839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com// Store the names of the filenames to report later which ones failed, succeeded, and were 8939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com// invalid. 9036c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// FIXME: Add more arrays, for more specific types of errors, and make the output simpler. 9136c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// If each array holds one type of error, the output can change from: 9236c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// 9336c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// Failures: 9436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// <image> failed for such and such reason 9536c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// <image> failed for some different reason 9636c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// 9736c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// to: 9836c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// 9936c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// Such and such failures: 10036c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// <image> 10136c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// 10236c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// Different reason failures: 10336c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// <image> 10436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// 10539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkTArray<SkString, false> gInvalidStreams; 10639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkTArray<SkString, false> gMissingCodecs; 10739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkTArray<SkString, false> gDecodeFailures; 10839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkTArray<SkString, false> gEncodeFailures; 10939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic SkTArray<SkString, false> gSuccessfulDecodes; 1107e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.comstatic SkTArray<SkString, false> gSuccessfulSubsetDecodes; 1117e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.comstatic SkTArray<SkString, false> gFailedSubsetDecodes; 112e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com// Files/subsets that do not have expectations. Not reported as a failure of the test so 113e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com// the bots will not turn red with each new image test. 114e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.comstatic SkTArray<SkString, false> gMissingExpectations; 115e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.comstatic SkTArray<SkString, false> gMissingSubsetExpectations; 11636c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com// For files that are expected to fail. 11736c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.comstatic SkTArray<SkString, false> gKnownFailures; 11836c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.comstatic SkTArray<SkString, false> gKnownSubsetFailures; 11939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 120bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereedstatic SkColorType gPrefColorType(kUnknown_SkColorType); 1216d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com 1226843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com// Expections read from a file specified by readExpectationsPath. The expectations must have been 1236843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com// previously written using createExpectationsPath. 1246843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.comSkAutoTUnref<skiagm::JsonExpectationsSource> gJsonExpectations; 1256843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 1265187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com/** 1275187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * Encode the bitmap to a file, written one of two ways, depending on 1285187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * FLAGS_writeChecksumBasedFilenames. If true, the final image will be 1295187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * written to: 1305187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * outDir/hashType/src/digestValue.png 1315187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * If false, the final image will be written out to: 1325187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * outDir/src.png 1335187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * The function returns whether the file was successfully written. 1345187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com */ 1355187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.comstatic bool write_bitmap(const char outDir[], const char src[], 1365187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const skiagm::BitmapAndDigest& bitmapAndDigest) { 1375187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkString filename; 1385187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (FLAGS_writeChecksumBasedFilenames) { 1395187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // First create the directory for the hashtype. 1405187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const SkString hashType = bitmapAndDigest.fDigest.getHashType(); 1415187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const SkString hashDir = SkOSPath::SkPathJoin(outDir, hashType.c_str()); 1425187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (!sk_mkdir(hashDir.c_str())) { 1435187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return false; 1445187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 1455187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 1465187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Now create the name of the folder specific to this image. 1475187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkString basename = SkOSPath::SkBasename(src); 1485187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const SkString imageDir = SkOSPath::SkPathJoin(hashDir.c_str(), basename.c_str()); 1495187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (!sk_mkdir(imageDir.c_str())) { 1505187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return false; 1515187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 1525187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 1535187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Name the file <digest>.png 1545187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkString checksumBasedName = bitmapAndDigest.fDigest.getDigestValue(); 1555187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com checksumBasedName.append(".png"); 1565187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 1575187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com filename = SkOSPath::SkPathJoin(imageDir.c_str(), checksumBasedName.c_str()); 1585187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } else { 1595187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com make_outname(&filename, outDir, src, ".png"); 1605187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 1615187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 1625187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const SkBitmap& bm = bitmapAndDigest.fBitmap; 1635187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (SkImageEncoder::EncodeFile(filename.c_str(), bm, SkImageEncoder::kPNG_Type, 100)) { 164de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com return true; 165de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com } 166de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com 16728fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org if (bm.colorType() == kN32_SkColorType) { 168de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com // First attempt at encoding failed, and the bitmap was already 8888. Making 169de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com // a copy is not going to help. 170de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com return false; 171de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com } 172de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com 173de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com // Encoding failed. Copy to 8888 and try again. 174546f70c82318d2fcdd9718966907d1edccd26cb6commit-bot@chromium.org SkBitmap bm8888; 17528fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org if (!bm.copyTo(&bm8888, kN32_SkColorType)) { 176de09af3fd86c430a9ed9741dfd11e79e19eee105scroggo@google.com return false; 177546f70c82318d2fcdd9718966907d1edccd26cb6commit-bot@chromium.org } 1785187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return SkImageEncoder::EncodeFile(filename.c_str(), bm8888, SkImageEncoder::kPNG_Type, 100); 17939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com} 18039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 1817e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com/** 1827e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com * Return a random SkIRect inside the range specified. 1837e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com * @param rand Random number generator. 1847e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com * @param maxX Exclusive maximum x-coordinate. SkIRect's fLeft and fRight will be 1857e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com * in the range [0, maxX) 1867e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com * @param maxY Exclusive maximum y-coordinate. SkIRect's fTop and fBottom will be 1877e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com * in the range [0, maxY) 1887e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com * @return SkIRect Non-empty, non-degenerate rectangle. 1897e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com */ 1907e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.comstatic SkIRect generate_random_rect(SkRandom* rand, int32_t maxX, int32_t maxY) { 1917e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkASSERT(maxX > 1 && maxY > 1); 1927e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com int32_t left = rand->nextULessThan(maxX); 1937e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com int32_t right = rand->nextULessThan(maxX); 1947e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com int32_t top = rand->nextULessThan(maxY); 1957e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com int32_t bottom = rand->nextULessThan(maxY); 1967e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkIRect rect = SkIRect::MakeLTRB(left, top, right, bottom); 1977e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com rect.sort(); 1987e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // Make sure rect is not empty. 1997e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (rect.fLeft == rect.fRight) { 2007e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (rect.fLeft > 0) { 2017e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com rect.fLeft--; 2027e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } else { 2037e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com rect.fRight++; 2047e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // This branch is only taken if 0 == rect.fRight, and 2057e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // maxX must be at least 2, so it must still be in 2067e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // range. 2077e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkASSERT(rect.fRight < maxX); 2087e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 2097e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 2107e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (rect.fTop == rect.fBottom) { 2117e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (rect.fTop > 0) { 2127e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com rect.fTop--; 2137e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } else { 2147e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com rect.fBottom++; 2157e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // Again, this must be in range. 2167e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkASSERT(rect.fBottom < maxY); 2177e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 2187e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 2197e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com return rect; 2207e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com} 2217e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com 2225187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com/** 2235187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * Return a string which includes the name of the file and the preferred config, 2245187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * as specified by "--config". The resulting string will match the pattern of 2255187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png" 2265187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com */ 2275187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.comstatic SkString create_json_key(const char* filename) { 2285187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkASSERT(FLAGS_config.count() == 1); 2295187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return SkStringPrintf("%s_%s.png", filename, FLAGS_config[0]); 2305187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com} 2315187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 2326843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com// Stored expectations to be written to a file if createExpectationsPath is specified. 2336843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.comstatic Json::Value gExpectationsToWrite; 2346843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 2356843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com/** 2365187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * If expectations are to be recorded, record the bitmap expectations into the global 2376843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com * expectations array. 2385187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * As is the case with reading expectations, the key used will combine the filename 2395187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * parameter with the preferred config, as specified by "--config", matching the 2405187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * pattern of gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png" 2416843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com */ 2425187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.comstatic void write_expectations(const skiagm::BitmapAndDigest& bitmapAndDigest, 2435187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const char* filename) { 2445187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const SkString name_config = create_json_key(filename); 2456843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com if (!FLAGS_createExpectationsPath.isEmpty()) { 2466843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com // Creates an Expectations object, and add it to the list to write. 2475187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com skiagm::Expectations expectation(bitmapAndDigest); 2486843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com Json::Value value = expectation.asJsonValue(); 2495187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gExpectationsToWrite[name_config.c_str()] = value; 2506843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 2516843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com} 2526843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 2536843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com/** 2545187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * If --readExpectationsPath is set, compare this bitmap to the json expectations 2555187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * provided. 2565187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * 2575187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * @param digest GmResultDigest, computed from the decoded bitmap, to compare to 2585187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * the existing expectation. 2595187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * @param filename String used to find the expected value. Will be combined with the 2605187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * preferred config, as specified by "--config", to match the pattern of 2615187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png". The resulting 2625187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * key will be used to find the proper expectations. 263e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com * @param failureArray Array to add a failure message to on failure. 26436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com * @param missingArray Array to add failure message to when missing image 26536c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com * expectation. 26636c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com * @param ignoreArray Array to add failure message to when the image does not match 26736c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com * the expectation, but this is a failure we can ignore. 2686ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com * @return bool True in any of these cases: 2696ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com * - the bitmap matches the expectation. 2706ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com * False in any of these cases: 271cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com * - there is no expectations file. 2726ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com * - there is an expectations file, but no expectation for this bitmap. 2736ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com * - there is an expectation for this bitmap, but it did not match. 2746ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com * - expectation could not be computed from the bitmap. 2756843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com */ 276cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.comstatic bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& digest, 277cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com const char* filename, 278e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com SkTArray<SkString, false>* failureArray, 27936c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com SkTArray<SkString, false>* missingArray, 28036c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com SkTArray<SkString, false>* ignoreArray) { 2815187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // For both writing and reading, the key for this entry will include the name 2825187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // of the file and the pref config, matching the pattern of gm_json.py's 2835187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // IMAGE_FILENAME_PATTERN: "name_config.png" 2845187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const SkString name_config = create_json_key(filename); 2855187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 286cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com if (!digest.isValid()) { 2876ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com if (failureArray != NULL) { 288cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com failureArray->push_back().printf("decoded %s, but could not create a GmResultDigest.", 2896ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com filename); 2906ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com } 2916ca30ca849cb5a5fde1f88c0c2397c7e865c3aecscroggo@google.com return false; 2926843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 2936843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 294cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com if (NULL == gJsonExpectations.get()) { 295cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com return false; 296cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } 297cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com 2985187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com skiagm::Expectations jsExpectation = gJsonExpectations->get(name_config.c_str()); 299cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com if (jsExpectation.empty()) { 300e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com if (missingArray != NULL) { 301e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com missingArray->push_back().printf("decoded %s, but could not find expectation.", 3026843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com filename); 3036843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 3046843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com return false; 3056843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 3066843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 307cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com if (jsExpectation.match(digest)) { 3086843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com return true; 3096843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 3106843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 31136c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com if (jsExpectation.ignoreFailure()) { 31236c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com ignoreArray->push_back().printf("%s does not match expectation, but this is known.", 31336c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com filename); 31436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com } else if (failureArray != NULL) { 3156843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com failureArray->push_back().printf("decoded %s, but the result does not match " 3166843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com "expectations.", 3176843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com filename); 3186843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 3196843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com return false; 3206843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com} 3216843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 3229da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com/** 3239da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * Helper function to write a bitmap subset to a file. Only called if subsets were created 3245187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * and a writePath was provided. Behaves differently depending on 3255187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * FLAGS_writeChecksumBasedFilenames. If true: 3265187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * Writes the image to a PNG file named according to the digest hash, as described in 3275187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * write_bitmap. 3285187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * If false: 3295187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * Creates a subdirectory called 'subsets' and writes a PNG to that directory. Also 3305187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * creates a subdirectory called 'extracted' and writes a bitmap created using 3315187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * extractSubset to a PNG in that directory. Both files will represent the same 3325187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * subrectangle and have the same name for convenient comparison. In this case, the 3335187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * digest is ignored. 3345187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * 3359da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * @param writePath Parent directory to hold the folders for the PNG files to write. Must 3369da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * not be NULL. 3375187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * @param subsetName Basename of the original file, with the dimensions of the subset tacked 3385187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * on. Used to name the new file/folder. 3395187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * @param bitmapAndDigestFromDecodeSubset SkBitmap (with digest) created by 3405187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * SkImageDecoder::DecodeSubset, using rect as the area to decode. 3419da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * @param rect Rectangle of the area decoded into bitmapFromDecodeSubset. Used to call 3429da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * extractSubset on originalBitmap to create a bitmap with the same dimensions/pixels as 3439da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * bitmapFromDecodeSubset (assuming decodeSubset worked properly). 3449da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * @param originalBitmap SkBitmap decoded from the same stream as bitmapFromDecodeSubset, 3459da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * using SkImageDecoder::decode to get the entire image. Used to create a PNG file for 3465187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com * comparison to the PNG created by bitmapAndDigestFromDecodeSubset's bitmap. 3479da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * @return bool Whether the function succeeded at drawing the decoded subset and the extracted 3489da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com * subset to files. 3499da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com */ 3505187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.comstatic bool write_subset(const char* writePath, const SkString& subsetName, 3515187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const skiagm::BitmapAndDigest bitmapAndDigestFromDecodeSubset, 3525187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkIRect rect, const SkBitmap& originalBitmap) { 3539da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com // All parameters must be valid. 3549da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com SkASSERT(writePath != NULL); 3559da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com 3565187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkString subsetPath; 3575187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (FLAGS_writeChecksumBasedFilenames) { 3585187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com subsetPath.set(writePath); 3595187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } else { 3605187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Create a subdirectory to hold the results of decodeSubset. 3615187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com subsetPath = SkOSPath::SkPathJoin(writePath, "subsets"); 3625187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (!sk_mkdir(subsetPath.c_str())) { 3635187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but " 3645187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com "failed to create a directory to write to.", 3655187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com subsetName.c_str()); 3665187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return false; 3675187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 3689da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com } 3695187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkAssertResult(write_bitmap(subsetPath.c_str(), subsetName.c_str(), 3705187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com bitmapAndDigestFromDecodeSubset)); 3715187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gSuccessfulSubsetDecodes.push_back().printf("\twrote %s", subsetName.c_str()); 3725187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 3735187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (!FLAGS_writeChecksumBasedFilenames) { 3745187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // FIXME: The goal of extracting the subset is for visual comparison/using skdiff/skpdiff. 3755187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Currently disabling for writeChecksumBasedFilenames since it will be trickier to 3765187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // determine which files to compare. 3775187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 3785187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Also use extractSubset from the original for visual comparison. 3795187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Write the result to a file in a separate subdirectory. 3805187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkBitmap extractedSubset; 3815187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (!originalBitmap.extractSubset(&extractedSubset, rect)) { 3825187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but failed " 3835187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com "to extract a similar subset for comparison.", 3845187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com subsetName.c_str()); 3855187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return false; 3865187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 3879da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com 3885187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkString dirExtracted = SkOSPath::SkPathJoin(writePath, "extracted"); 3895187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (!sk_mkdir(dirExtracted.c_str())) { 3905187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gFailedSubsetDecodes.push_back().printf("Successfully decoded subset%s, but failed " 3915187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com "to create a directory for extractSubset " 3925187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com "comparison.", 3935187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com subsetName.c_str()); 3945187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return false; 3955187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 3969da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com 3975187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com skiagm::BitmapAndDigest bitmapAndDigestFromExtractSubset(extractedSubset); 3985187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkAssertResult(write_bitmap(dirExtracted.c_str(), subsetName.c_str(), 3995187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com bitmapAndDigestFromExtractSubset)); 4005187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 4019da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com return true; 4029da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com} 4039da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com 404cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com// FIXME: This test could be run on windows/mac once we remove their dependence on 405cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com// getLength. See https://code.google.com/p/skia/issues/detail?id=1570 406cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 407cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com 408cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com/** 409cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * Dummy class for testing to ensure that a stream without a length decodes the same 410cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * as a stream with a length. 411cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com */ 412cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.comclass FILEStreamWithoutLength : public SkFILEStream { 413cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.compublic: 414cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com FILEStreamWithoutLength(const char path[]) 415cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com : INHERITED(path) {} 416cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com 417cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com virtual bool hasLength() const SK_OVERRIDE { 418cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com return false; 419cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com } 420cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com 421cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.comprivate: 422cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com typedef SkFILEStream INHERITED; 423cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com}; 424cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com 425cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com/** 426cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * Test that decoding a stream which reports to not have a length still results in the 427cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * same image as if it did report to have a length. Assumes that codec was used to 428cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * successfully decode the file using SkFILEStream. 429cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * @param srcPath The path to the file, for recreating the length-less stream. 430cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * @param codec The SkImageDecoder originally used to decode srcPath, which will be used 431cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * again to decode the length-less stream. 432cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * @param digest GmResultDigest computed from decoding the stream the first time. 433cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com * Decoding the length-less stream is expected to result in a matching digest. 434cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com */ 435cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.comstatic void test_stream_without_length(const char srcPath[], SkImageDecoder* codec, 436cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com const skiagm::GmResultDigest& digest) { 437cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com if (!digest.isValid()) { 438cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com // An error was already reported. 439cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com return; 440cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com } 441cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com SkASSERT(srcPath); 442cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com SkASSERT(codec); 443cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com FILEStreamWithoutLength stream(srcPath); 444cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com // This will only be called after a successful decode. Creating a stream from the same 445cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com // path should never fail. 446cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com SkASSERT(stream.isValid()); 447cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com SkBitmap bm; 448bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed if (!codec->decode(&stream, &bm, gPrefColorType, SkImageDecoder::kDecodePixels_Mode)) { 449cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com gDecodeFailures.push_back().appendf("Without using getLength, %s failed to decode\n", 450cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com srcPath); 451cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com return; 452cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com } 453cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com skiagm::GmResultDigest lengthLessDigest(bm); 454cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com if (!lengthLessDigest.isValid()) { 455cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com gDecodeFailures.push_back().appendf("Without using getLength, %s failed to build " 456cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com "a digest\n", srcPath); 457cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com return; 458cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com } 459cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com if (!lengthLessDigest.equals(digest)) { 460cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com gDecodeFailures.push_back().appendf("Without using getLength, %s did not match digest " 461cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com "that uses getLength\n", srcPath); 462cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com } 463cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com} 464cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com#endif // defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 465cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com 4665187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com/** 46724c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org * Replaces all instances of oldChar with newChar in str. 46824c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org * 46924c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org * TODO: This function appears here and in picture_utils.[cpp|h] ; 47024c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org * we should add the implementation to src/core/SkString.cpp, write tests for it, 47124c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org * and remove it from elsewhere. 4725187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com */ 4735187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.comstatic void replace_char(SkString* str, const char oldChar, const char newChar) { 4745187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (NULL == str) { 4755187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com return; 4765187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 4775187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com for (size_t i = 0; i < str->size(); ++i) { 4785187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (oldChar == str->operator[](i)) { 4795187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com str->operator[](i) = newChar; 4805187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 4815187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com } 4825187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com} 4835187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 48439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic void decodeFileAndWrite(const char srcPath[], const SkString* writePath) { 48539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkBitmap bitmap; 48639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkFILEStream stream(srcPath); 48739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (!stream.isValid()) { 48839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com gInvalidStreams.push_back().set(srcPath); 48939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return; 49039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 49139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 49239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkImageDecoder* codec = SkImageDecoder::Factory(&stream); 49339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (NULL == codec) { 49439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com gMissingCodecs.push_back().set(srcPath); 49539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return; 49639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 49739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 49839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkAutoTDelete<SkImageDecoder> ad(codec); 49939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 5008d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com codec->setSkipWritingZeroes(FLAGS_skip); 501dac4a1d518a4788c3e2475d68cbe8683b4a448ffcommit-bot@chromium.org codec->setSampleSize(FLAGS_sampleSize); 50239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com stream.rewind(); 50339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 5046843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com // Create a string representing just the filename itself, for use in json expectations. 505ccd7afb6fb2df9774e57fb4d7f62f9504cabf03escroggo@google.com SkString basename = SkOSPath::SkBasename(srcPath); 5065187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Replace '_' with '-', so that the names can fit gm_json.py's IMAGE_FILENAME_PATTERN 5075187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com replace_char(&basename, '_', '-'); 5085187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // Replace '.' with '-', so the output filename can still retain the original file extension, 5095187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com // but still end up with only one '.', which denotes the actual extension of the final file. 5105187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com replace_char(&basename, '.', '-'); 511ccd7afb6fb2df9774e57fb4d7f62f9504cabf03escroggo@google.com const char* filename = basename.c_str(); 5126843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 513bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed if (!codec->decode(&stream, &bitmap, gPrefColorType, SkImageDecoder::kDecodePixels_Mode)) { 51436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com if (NULL != gJsonExpectations.get()) { 5155187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com const SkString name_config = create_json_key(filename); 5165187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com skiagm::Expectations jsExpectations = gJsonExpectations->get(name_config.c_str()); 51736c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com if (jsExpectations.ignoreFailure()) { 51836c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com // This is a known failure. 51936c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com gKnownFailures.push_back().appendf( 52036c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com "failed to decode %s, which is a known failure.", srcPath); 52136c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com return; 52236c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com } 52336c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com if (jsExpectations.empty()) { 52436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com // This is a failure, but it is a new file. Mark it as missing, with 52536c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com // a note that it should be marked failing. 52636c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com gMissingExpectations.push_back().appendf( 52736c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com "new file %s (with no expectations) FAILED to decode.", srcPath); 52836c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com return; 52936c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com } 530bc91e8b7d759e40d669f153ac2feff39b60a9059scroggo@google.com } 53136c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com 53236c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com // If there was a failure, and either there was no expectations file, or 53336c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com // the expectations file listed a valid expectation, report the failure. 53436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com gDecodeFailures.push_back().set(srcPath); 535bc91e8b7d759e40d669f153ac2feff39b60a9059scroggo@google.com return; 536bc91e8b7d759e40d669f153ac2feff39b60a9059scroggo@google.com } 537bc91e8b7d759e40d669f153ac2feff39b60a9059scroggo@google.com 5386f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com // Test decoding just the bounds. The bounds should always match. 5396f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com { 5406f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com stream.rewind(); 5416f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com SkBitmap dim; 5426f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com if (!codec->decode(&stream, &dim, SkImageDecoder::kDecodeBounds_Mode)) { 5436f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com SkString failure = SkStringPrintf("failed to decode bounds for %s", srcPath); 5446f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com gDecodeFailures.push_back() = failure; 5456f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com } else { 5466f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com // Now check that the bounds match: 5476f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com if (dim.width() != bitmap.width() || dim.height() != bitmap.height()) { 5486f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com SkString failure = SkStringPrintf("bounds do not match for %s", srcPath); 5496f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com gDecodeFailures.push_back() = failure; 5506f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com } 5516f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com } 5526f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com } 5536f67b3b2d963710fcace0830977382197dbfe8ccscroggo@google.com 5545187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com skiagm::BitmapAndDigest bitmapAndDigest(bitmap); 5555187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (compare_to_expectations_if_necessary(bitmapAndDigest.fDigest, filename, &gDecodeFailures, 5565187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com &gMissingExpectations, &gKnownFailures)) { 5576843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.width(), 5586843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com bitmap.height()); 559cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } else if (!FLAGS_mismatchPath.isEmpty()) { 5605187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (write_bitmap(FLAGS_mismatchPath[0], filename, bitmapAndDigest)) { 5615187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gSuccessfulDecodes.push_back().appendf("\twrote %s", filename); 562cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } else { 5635187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gEncodeFailures.push_back().set(filename); 564cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } 565cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } 566cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com 567cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com// FIXME: This test could be run on windows/mac once we remove their dependence on 568cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com// getLength. See https://code.google.com/p/skia/issues/detail?id=1570 569cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 5705187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com test_stream_without_length(srcPath, codec, bitmapAndDigest.fDigest); 571cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com#endif 572cd7a73c200cc4035f3cc7af157176ca0cf7a07d1scroggo@google.com 573cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com if (writePath != NULL) { 5745187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (write_bitmap(writePath->c_str(), filename, bitmapAndDigest)) { 5755187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gSuccessfulDecodes.push_back().appendf("\twrote %s", filename); 576cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } else { 5775187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com gEncodeFailures.push_back().set(filename); 578cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } 5796843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 5806843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 5815187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com write_expectations(bitmapAndDigest, filename); 58239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 5837e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (FLAGS_testSubsetDecoding) { 5840018f75f2f2d19772db4f47e1885597230e23f14scroggo@google.com SkDEBUGCODE(bool couldRewind =) stream.rewind(); 5857e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkASSERT(couldRewind); 5867e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com int width, height; 5877e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // Build the tile index for decoding subsets. If the image is 1x1, skip subset 5887e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // decoding since there are no smaller subsets. 5897e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (codec->buildTileIndex(&stream, &width, &height) && width > 1 && height > 1) { 5907e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkASSERT(bitmap.width() == width && bitmap.height() == height); 5917e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // Call decodeSubset multiple times: 5927e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkRandom rand(0); 5937e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com for (int i = 0; i < 5; i++) { 5947e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkBitmap bitmapFromDecodeSubset; 5957e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com // FIXME: Come up with a more representative set of rectangles. 5967e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com SkIRect rect = generate_random_rect(&rand, width, height); 5978ff38ccb40ee4cf5f7f4ea2be424419d1124511fepoger SkString subsetDim = SkStringPrintf("%d_%d_%d_%d", rect.fLeft, rect.fTop, 5987e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com rect.fRight, rect.fBottom); 599bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed if (codec->decodeSubset(&bitmapFromDecodeSubset, rect, gPrefColorType)) { 6005187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com SkString subsetName = SkStringPrintf("%s-%s", filename, subsetDim.c_str()); 6015187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com skiagm::BitmapAndDigest subsetBitmapAndDigest(bitmapFromDecodeSubset); 6025187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com if (compare_to_expectations_if_necessary(subsetBitmapAndDigest.fDigest, 6036843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com subsetName.c_str(), 604e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com &gFailedSubsetDecodes, 60536c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com &gMissingSubsetExpectations, 60636c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com &gKnownSubsetFailures)) { 6076843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com gSuccessfulSubsetDecodes.push_back().printf("Decoded subset %s from %s", 6086843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com subsetDim.c_str(), srcPath); 609cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com } else if (!FLAGS_mismatchPath.isEmpty()) { 6105187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com write_subset(FLAGS_mismatchPath[0], subsetName, 6115187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com subsetBitmapAndDigest, rect, bitmap); 6126843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 6136843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 6145187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com write_expectations(subsetBitmapAndDigest, subsetName.c_str()); 6155187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com 6167e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (writePath != NULL) { 6175187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com write_subset(writePath->c_str(), subsetName, 6185187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com subsetBitmapAndDigest, rect, bitmap); 6197e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 6207e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } else { 6219da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com gFailedSubsetDecodes.push_back().printf("Failed to decode region %s from %s", 6227e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com subsetDim.c_str(), srcPath); 6237e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 6247e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 6257e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 6267e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 6279da0e1de1d0615038e27fc894d1fcc44562cecf5scroggo@google.com 628546f70c82318d2fcdd9718966907d1edccd26cb6commit-bot@chromium.org // Do not attempt to re-encode A8, since our image encoders do not support encoding to A8. 629bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed if (FLAGS_reencode && bitmap.colorType() != kAlpha_8_SkColorType) { 63039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com // Encode to the format the file was originally in, or PNG if the encoder for the same 63139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com // format is unavailable. 63239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkImageDecoder::Format format = codec->getFormat(); 63339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (SkImageDecoder::kUnknown_Format == format) { 63439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (stream.rewind()) { 63539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com format = SkImageDecoder::GetStreamFormat(&stream); 63639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 63739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (SkImageDecoder::kUnknown_Format == format) { 63839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com const char* dot = strrchr(srcPath, '.'); 63939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (NULL != dot) { 64039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com format = guess_format_from_suffix(dot); 64139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 64239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (SkImageDecoder::kUnknown_Format == format) { 64339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkDebugf("Could not determine type for '%s'\n", srcPath); 64439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com format = SkImageDecoder::kPNG_Format; 64539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 64639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 64739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 64839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } else { 64939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkASSERT(!stream.rewind() || SkImageDecoder::GetStreamFormat(&stream) == format); 65039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 65139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkImageEncoder::Type type = format_to_type(format); 65239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com // format should never be kUnknown_Format, so type should never be kUnknown_Type. 65339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkASSERT(type != SkImageEncoder::kUnknown_Type); 65439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 65539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkImageEncoder* encoder = SkImageEncoder::Create(type); 65639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (NULL == encoder) { 65739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com type = SkImageEncoder::kPNG_Type; 65839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com encoder = SkImageEncoder::Create(type); 65939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkASSERT(encoder); 66039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 66139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkAutoTDelete<SkImageEncoder> ade(encoder); 66239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com // Encode to a stream. 66339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkDynamicMemoryWStream wStream; 66439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (!encoder->encodeStream(&wStream, bitmap, 100)) { 66539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com gEncodeFailures.push_back().printf("Failed to reencode %s to type '%s'", srcPath, 66639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com suffix_for_type(type)); 66739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return; 66839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 66939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 67039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkAutoTUnref<SkData> data(wStream.copyToData()); 67139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if (writePath != NULL && type != SkImageEncoder::kPNG_Type) { 672cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com // Write the encoded data to a file. Do not write to PNG, which was already written. 67339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkString outPath; 6745187c4313cd6b1dea82c43fa5af466576e4025f1scroggo@google.com make_outname(&outPath, writePath->c_str(), filename, suffix_for_type(type)); 67539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkFILEWStream file(outPath.c_str()); 67639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com if(file.write(data->data(), data->size())) { 67739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str()); 67839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } else { 67939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com gEncodeFailures.push_back().printf("Failed to write %s", outPath.c_str()); 68039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 68139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 68239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com // Ensure that the reencoded data can still be decoded. 68339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkMemoryStream memStream(data); 68439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkBitmap redecodedBitmap; 68539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkImageDecoder::Format formatOnSecondDecode; 686bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed if (SkImageDecoder::DecodeStream(&memStream, &redecodedBitmap, gPrefColorType, 687bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed SkImageDecoder::kDecodePixels_Mode, 688bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed &formatOnSecondDecode)) { 68939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com SkASSERT(format_to_type(formatOnSecondDecode) == type); 69039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } else { 69139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com gDecodeFailures.push_back().printf("Failed to redecode %s after reencoding to '%s'", 69239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com srcPath, suffix_for_type(type)); 69339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 69439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com } 695b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com} 696b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 69739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com/////////////////////////////////////////////////////////////////////////////// 69839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com 699b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com// If strings is not empty, print title, followed by each string on its own line starting 700b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com// with a tab. 70139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com// @return bool True if strings had at least one entry. 70239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.comstatic bool print_strings(const char* title, const SkTArray<SkString, false>& strings) { 703b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com if (strings.count() > 0) { 704b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkDebugf("%s:\n", title); 705b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com for (int i = 0; i < strings.count(); i++) { 706b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkDebugf("\t%s\n", strings[i].c_str()); 707b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com } 708b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkDebugf("\n"); 70939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return true; 710b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com } 71139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return false; 712af459795e393dabd8ea02afade5609935c0d9509reed@android.com} 713af459795e393dabd8ea02afade5609935c0d9509reed@android.com 7146843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com/** 7156843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com * If directory is non null and does not end with a path separator, append one. 7166843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com * @param directory SkString representing the path to a directory. If the last character is not a 7176843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com * path separator (specific to the current OS), append one. 7186843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com */ 7196843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.comstatic void append_path_separator_if_necessary(SkString* directory) { 7206843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com if (directory != NULL && directory->c_str()[directory->size() - 1] != SkPATH_SEPARATOR) { 7216843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com directory->appendf("%c", SkPATH_SEPARATOR); 7226843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 7236843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com} 7246843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 725925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com/** 726925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com * Return true if the filename represents an image. 727925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com */ 728925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.comstatic bool is_image_file(const char* filename) { 729925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com const char* gImageExtensions[] = { 730925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com ".png", ".PNG", ".jpg", ".JPG", ".jpeg", ".JPEG", ".bmp", ".BMP", 731925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com ".webp", ".WEBP", ".ico", ".ICO", ".wbmp", ".WBMP", ".gif", ".GIF" 732925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com }; 733925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com for (size_t i = 0; i < SK_ARRAY_COUNT(gImageExtensions); ++i) { 734925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com if (SkStrEndsWith(filename, gImageExtensions[i])) { 735925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com return true; 736925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com } 737925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com } 738925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com return false; 739925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com} 740925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com 7415987f58036574ccf23049b5fe71f29a441d0641dcaryclark@google.comint tool_main(int argc, char** argv); 7425987f58036574ccf23049b5fe71f29a441d0641dcaryclark@google.comint tool_main(int argc, char** argv) { 743b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkCommandLineFlags::SetUsage("Decode files, and optionally write the results to files."); 744b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkCommandLineFlags::Parse(argc, argv); 745b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 746b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com if (FLAGS_readPath.count() < 1) { 747b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkDebugf("Folder(s) or image(s) to decode are required.\n"); 748b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com return -1; 749b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com } 750b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 751b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 752af459795e393dabd8ea02afade5609935c0d9509reed@android.com SkAutoGraphics ag; 753b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 7543832da1e9cf6066d22007881888d65405d8cc6a5scroggo@google.com if (!FLAGS_readExpectationsPath.isEmpty() && sk_exists(FLAGS_readExpectationsPath[0])) { 7556843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com gJsonExpectations.reset(SkNEW_ARGS(skiagm::JsonExpectationsSource, 7566843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com (FLAGS_readExpectationsPath[0]))); 7576843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 7586843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com 759af459795e393dabd8ea02afade5609935c0d9509reed@android.com SkString outDir; 760b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkString* outDirPtr; 761af459795e393dabd8ea02afade5609935c0d9509reed@android.com 762b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com if (FLAGS_writePath.count() == 1) { 763b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com outDir.set(FLAGS_writePath[0]); 7646843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com append_path_separator_if_necessary(&outDir); 765b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com outDirPtr = &outDir; 766b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com } else { 767b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com outDirPtr = NULL; 768af459795e393dabd8ea02afade5609935c0d9509reed@android.com } 769af459795e393dabd8ea02afade5609935c0d9509reed@android.com 7706d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com if (FLAGS_config.count() == 1) { 7716d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com // Only consider the first config specified on the command line. 7726d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com const char* config = FLAGS_config[0]; 7736d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com if (0 == strcmp(config, "8888")) { 774bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed gPrefColorType = kN32_SkColorType; 7756d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com } else if (0 == strcmp(config, "565")) { 776bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed gPrefColorType = kRGB_565_SkColorType; 7776d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com } else if (0 == strcmp(config, "A8")) { 778bfefc7c95fc0e8ebd5000c68f6d16e1a3ea0e71ereed gPrefColorType = kAlpha_8_SkColorType; 7796d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com } else if (0 != strcmp(config, "None")) { 7806d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com SkDebugf("Invalid preferred config\n"); 7816d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com return -1; 7826d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com } 7836d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com } 7846d99de11c4cf245d91398de7041bec55b1b9ac05scroggo@google.com 785b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com for (int i = 0; i < FLAGS_readPath.count(); i++) { 7862b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com const char* readPath = FLAGS_readPath[i]; 7872b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com if (strlen(readPath) < 1) { 788b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com break; 789af459795e393dabd8ea02afade5609935c0d9509reed@android.com } 7902b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com if (sk_isdir(readPath)) { 7912b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com const char* dir = readPath; 7922b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com SkOSFile::Iter iter(dir); 7932b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com SkString filename; 7942b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com while (iter.next(&filename)) { 795925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com if (!is_image_file(filename.c_str())) { 796925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com continue; 797925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com } 7982b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com SkString fullname = SkOSPath::SkPathJoin(dir, filename.c_str()); 799b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com decodeFileAndWrite(fullname.c_str(), outDirPtr); 8002b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com } 801925cdca8055fe6d6aab7c271d93d224d9b4e4fc8scroggo@google.com } else if (sk_exists(readPath) && is_image_file(readPath)) { 8022b9424b3420ac4df2c3104f31d3cbdadda1d4ffdscroggo@google.com decodeFileAndWrite(readPath, outDirPtr); 803af459795e393dabd8ea02afade5609935c0d9509reed@android.com } 804af459795e393dabd8ea02afade5609935c0d9509reed@android.com } 805af459795e393dabd8ea02afade5609935c0d9509reed@android.com 8066843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com if (!FLAGS_createExpectationsPath.isEmpty()) { 8076843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com // Use an empty value for everything besides expectations, since the reader only cares 8086843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com // about the expectations. 8096843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com Json::Value nullValue; 8106843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com Json::Value root = skiagm::CreateJsonTree(gExpectationsToWrite, nullValue, nullValue, 8116843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com nullValue, nullValue); 8126843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com std::string jsonStdString = root.toStyledString(); 813cf5eb6ab25057ee4bcaaee88f819a293e9c47ac6scroggo@google.com SkFILEWStream stream(FLAGS_createExpectationsPath[0]); 8146843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com stream.write(jsonStdString.c_str(), jsonStdString.length()); 8156843bdb7061364c100990e7e0feb3757fca08bb0scroggo@google.com } 816b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com // Add some space, since codecs may print warnings without newline. 817b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com SkDebugf("\n\n"); 818b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 81939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com bool failed = print_strings("Invalid files", gInvalidStreams); 82039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com failed |= print_strings("Missing codec", gMissingCodecs); 82139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com failed |= print_strings("Failed to decode", gDecodeFailures); 82239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com failed |= print_strings("Failed to encode", gEncodeFailures); 82339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com print_strings("Decoded", gSuccessfulDecodes); 824e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com print_strings("Missing expectations", gMissingExpectations); 825b41ff95cc0879884814375a37d07fd14f9519676scroggo@google.com 8267e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com if (FLAGS_testSubsetDecoding) { 8277e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com failed |= print_strings("Failed subset decodes", gFailedSubsetDecodes); 8287e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com print_strings("Decoded subsets", gSuccessfulSubsetDecodes); 829e339eb054b63a6c5496f55ca6b9b9c9860a0cce2scroggo@google.com print_strings("Missing subset expectations", gMissingSubsetExpectations); 83036c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com print_strings("Known subset failures", gKnownSubsetFailures); 8317e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com } 8327e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com 83336c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com print_strings("Known failures", gKnownFailures); 83436c5bdb097f13ede159543a57b7035dbf1f4b3cbscroggo@google.com 83539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com return failed ? -1 : 0; 836af459795e393dabd8ea02afade5609935c0d9509reed@android.com} 837af459795e393dabd8ea02afade5609935c0d9509reed@android.com 8385987f58036574ccf23049b5fe71f29a441d0641dcaryclark@google.com#if !defined SK_BUILD_FOR_IOS 8395987f58036574ccf23049b5fe71f29a441d0641dcaryclark@google.comint main(int argc, char * const argv[]) { 8405987f58036574ccf23049b5fe71f29a441d0641dcaryclark@google.com return tool_main(argc, (char**) argv); 8415987f58036574ccf23049b5fe71f29a441d0641dcaryclark@google.com} 8425987f58036574ccf23049b5fe71f29a441d0641dcaryclark@google.com#endif 843