/// If outputDir.isEmpty(), don't write out diff files. static void create_diff_images (DiffMetricProc dmp, const int colorThreshold, const SkString& baseFile, const SkString& comparisonFile, const SkString& outputDir, const SkString& outputFilename, DiffRecord* drp) { SkASSERT(!baseFile.isEmpty()); SkASSERT(!comparisonFile.isEmpty()); drp->fBase.fFilename = baseFile; drp->fBase.fFullPath = baseFile; drp->fBase.fStatus = DiffResource::kSpecified_Status; drp->fComparison.fFilename = comparisonFile; drp->fComparison.fFullPath = comparisonFile; drp->fComparison.fStatus = DiffResource::kSpecified_Status; SkAutoDataUnref baseFileBits(read_file(drp->fBase.fFullPath.c_str())); if (baseFileBits) { drp->fBase.fStatus = DiffResource::kRead_Status; } SkAutoDataUnref comparisonFileBits(read_file(drp->fComparison.fFullPath.c_str())); if (comparisonFileBits) { drp->fComparison.fStatus = DiffResource::kRead_Status; } if (nullptr == baseFileBits || nullptr == comparisonFileBits) { if (nullptr == baseFileBits) { drp->fBase.fStatus = DiffResource::kCouldNotRead_Status; } if (nullptr == comparisonFileBits) { drp->fComparison.fStatus = DiffResource::kCouldNotRead_Status; } drp->fResult = DiffRecord::kCouldNotCompare_Result; return; } if (are_buffers_equal(baseFileBits, comparisonFileBits)) { drp->fResult = DiffRecord::kEqualBits_Result; return; } get_bitmap(baseFileBits, drp->fBase, SkImageDecoder::kDecodePixels_Mode); get_bitmap(comparisonFileBits, drp->fComparison, SkImageDecoder::kDecodePixels_Mode); if (DiffResource::kDecoded_Status != drp->fBase.fStatus || DiffResource::kDecoded_Status != drp->fComparison.fStatus) { drp->fResult = DiffRecord::kCouldNotCompare_Result; return; } create_and_write_diff_image(drp, dmp, colorThreshold, outputDir, outputFilename); //TODO: copy fBase.fFilename and fComparison.fFilename to outputDir // svn and git often present tmp files to diff tools which are promptly deleted //TODO: serialize drp to outputDir // write a tool to deserialize them and call print_diff_page SkASSERT(DiffRecord::kUnknown_Result != drp->fResult); }
void SkSVGDevice::AutoElement::addTextAttributes(const SkPaint& paint) { this->addAttribute("font-size", paint.getTextSize()); if (const char* textAlign = svg_text_align(paint.getTextAlign())) { this->addAttribute("text-anchor", textAlign); } SkString familyName; SkTHashSet<SkString> familySet; SkAutoTUnref<const SkTypeface> tface(paint.getTypeface() ? SkRef(paint.getTypeface()) : SkTypeface::RefDefault()); SkASSERT(tface); SkTypeface::Style style = tface->style(); if (style & SkTypeface::kItalic) { this->addAttribute("font-style", "italic"); } if (style & SkTypeface::kBold) { this->addAttribute("font-weight", "bold"); } SkAutoTUnref<SkTypeface::LocalizedStrings> familyNameIter(tface->createFamilyNameIterator()); SkTypeface::LocalizedString familyString; while (familyNameIter->next(&familyString)) { if (familySet.contains(familyString.fString)) { continue; } familySet.add(familyString.fString); familyName.appendf((familyName.isEmpty() ? "%s" : ", %s"), familyString.fString.c_str()); } if (!familyName.isEmpty()) { this->addAttribute("font-family", familyName); } }
DEF_GPUTEST_FOR_ALL_CONTEXTS(GrDrawTargetPrint, reporter, ctxInfo) { // This used to assert. SkString result = ctxInfo.fGrContext->caps()->dump(); SkASSERT(!result.isEmpty()); SkString shaderResult = ctxInfo.fGrContext->caps()->shaderCaps()->dump(); SkASSERT(!shaderResult.isEmpty()); }
static void run_test(skiatest::Test* test) { struct : public skiatest::Reporter { void reportFailed(const skiatest::Failure& failure) override { fail(failure.toString()); JsonWriter::AddTestFailure(failure); } bool allowExtendedTest() const override { return FLAGS_pathOpsExtended; } bool verbose() const override { return FLAGS_veryVerbose; } } reporter; SkString note; SkString whyBlacklisted = is_blacklisted("_", "tests", "_", test->name); if (!whyBlacklisted.isEmpty()) { note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); } WallTimer timer; timer.start(); if (!FLAGS_dryRun && whyBlacklisted.isEmpty()) { start("unit", "test", "", test->name); GrContextFactory factory; if (FLAGS_pre_log) { SkDebugf("\nRunning test %s", test->name); } test->proc(&reporter, &factory); } timer.end(); done(timer.fWall, "unit", "test", "", test->name, note, ""); }
static void write_string(SkWStream* stream, const SkString& string, uint32_t id) { if (!string.isEmpty()) { stream->writePackedUInt(id); stream->writePackedUInt(string.size()); stream->write(string.c_str(), string.size()); } }
static AtomicString getFamilyNameForCharacter(UChar32 c, UScriptCode script) { // This is a hack to use the preferred font for CJK scripts. // FIXME: Use new Skia API once Android system supports per-family and per-script fallback fonts. const char* locale; switch (script) { case USCRIPT_SIMPLIFIED_HAN: locale = "zh-CN"; break; case USCRIPT_TRADITIONAL_HAN: locale = "zh-TW"; break; case USCRIPT_KATAKANA_OR_HIRAGANA: locale = "ja"; break; case USCRIPT_HANGUL: locale = "ko"; break; default: locale = 0; break; } SkString skiaFamilyName; if (!SkGetFallbackFamilyNameForChar(c, locale, &skiaFamilyName) || skiaFamilyName.isEmpty()) return emptyAtom; return skiaFamilyName.c_str(); }
static void test_abortWithFile(skiatest::Reporter* reporter) { SkString tmpDir = skiatest::GetTmpDir(); if (tmpDir.isEmpty()) { ERRORF(reporter, "missing tmpDir."); return; } SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf"); if (!SkFILEWStream(path.c_str()).isValid()) { ERRORF(reporter, "unable to write to: %s", path.c_str()); return; } // Make sure doc's destructor is called to flush. { SkFILEWStream stream(path.c_str()); auto doc = SkPDF::MakeDocument(&stream); SkCanvas* canvas = doc->beginPage(100, 100); canvas->drawColor(SK_ColorRED); doc->endPage(); doc->abort(); } FILE* file = fopen(path.c_str(), "r"); // Test that only the header is written, not the full document. char buffer[256]; REPORTER_ASSERT(reporter, fread(buffer, 1, sizeof(buffer), file) < sizeof(buffer)); fclose(file); }
static void test_abortWithFile(skiatest::Reporter* reporter) { SkString tmpDir = skiatest::GetTmpDir(); if (tmpDir.isEmpty()) { return; // TODO(edisonn): unfortunatelly this pattern is used in other // tests, but if GetTmpDir() starts returning and empty dir // allways, then all these tests will be disabled. } SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf"); // Make sure doc's destructor is called to flush. { SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path.c_str())); SkCanvas* canvas = doc->beginPage(100, 100); canvas->drawColor(SK_ColorRED); doc->endPage(); doc->abort(); } FILE* file = fopen(path.c_str(), "r"); // The created file should be empty. char buffer[100]; REPORTER_ASSERT(reporter, fread(buffer, 1, 1, file) == 0); fclose(file); }
static void test_files(skiatest::Reporter* reporter) { SkString tmpDir = skiatest::Test::GetTmpDir(); if (tmpDir.isEmpty()) { return; } SkString path = SkOSPath::SkPathJoin(tmpDir.c_str(), "data_test"); const char s[] = "abcdefghijklmnopqrstuvwxyz"; { SkFILEWStream writer(path.c_str()); if (!writer.isValid()) { ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str()); return; } writer.write(s, 26); } SkFILE* file = sk_fopen(path.c_str(), kRead_SkFILE_Flag); SkAutoTUnref<SkData> r1(SkData::NewFromFILE(file)); REPORTER_ASSERT(reporter, r1.get() != NULL); REPORTER_ASSERT(reporter, r1->size() == 26); REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(r1->data()), s, 26) == 0); int fd = sk_fileno(file); SkAutoTUnref<SkData> r2(SkData::NewFromFD(fd)); REPORTER_ASSERT(reporter, r2.get() != NULL); REPORTER_ASSERT(reporter, r2->size() == 26); REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(r2->data()), s, 26) == 0); }
static sk_sp<SkTypeface_AndroidSystem> find_family_style_character( const SkTArray<NameToFamily, true>& fallbackNameToFamilyMap, const SkFontStyle& style, bool elegant, const SkString& langTag, SkUnichar character) { for (int i = 0; i < fallbackNameToFamilyMap.count(); ++i) { SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet; sk_sp<SkTypeface_AndroidSystem> face(family->matchStyle(style)); if (!langTag.isEmpty() && !face->fLang.getTag().startsWith(langTag.c_str())) { continue; } if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) { continue; } SkPaint paint; paint.setTypeface(face); paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); uint16_t glyphID; paint.textToGlyphs(&character, sizeof(character), &glyphID); if (glyphID != 0) { return face; } } return nullptr; }
static void test_file(skiatest::Reporter* reporter) { SkString tmpDir = skiatest::GetTmpDir(); if (tmpDir.isEmpty()) { ERRORF(reporter, "missing tmpDir."); return; } SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf"); if (!SkFILEWStream(path.c_str()).isValid()) { ERRORF(reporter, "unable to write to: %s", path.c_str()); return; } { SkFILEWStream stream(path.c_str()); auto doc = SkPDF::MakeDocument(&stream); SkCanvas* canvas = doc->beginPage(100, 100); canvas->drawColor(SK_ColorRED); doc->endPage(); doc->close(); } FILE* file = fopen(path.c_str(), "r"); REPORTER_ASSERT(reporter, file != nullptr); char header[100]; REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0); REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0); fclose(file); }
static void test_file(skiatest::Reporter* reporter) { SkString tmpDir = skiatest::GetTmpDir(); if (tmpDir.isEmpty()) { return; // TODO(edisonn): unfortunatelly this pattern is used in other // tests, but if GetTmpDir() starts returning and empty dir // allways, then all these tests will be disabled. } SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf"); SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path.c_str())); SkCanvas* canvas = doc->beginPage(100, 100); canvas->drawColor(SK_ColorRED); doc->endPage(); doc->close(); FILE* file = fopen(path.c_str(), "r"); REPORTER_ASSERT(reporter, file != nullptr); char header[100]; REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0); REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0); fclose(file); }
static void TestWStream(skiatest::Reporter* reporter) { SkDynamicMemoryWStream ds; const char s[] = "abcdefghijklmnopqrstuvwxyz"; int i; for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, ds.write(s, 26)); } REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26); char* dst = new char[100 * 26 + 1]; dst[100*26] = '*'; ds.copyTo(dst); REPORTER_ASSERT(reporter, dst[100*26] == '*'); for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); } { std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream()); REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength()); REPORTER_ASSERT(reporter, ds.bytesWritten() == 0); test_loop_stream(reporter, stream.get(), s, 26, 100); std::unique_ptr<SkStreamAsset> stream2(stream->duplicate()); test_loop_stream(reporter, stream2.get(), s, 26, 100); std::unique_ptr<SkStreamAsset> stream3(stream->fork()); REPORTER_ASSERT(reporter, stream3->isAtEnd()); char tmp; size_t bytes = stream->read(&tmp, 1); REPORTER_ASSERT(reporter, 0 == bytes); stream3->rewind(); test_loop_stream(reporter, stream3.get(), s, 26, 100); } for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, ds.write(s, 26)); } REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26); { // Test that this works after a snapshot. std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream()); REPORTER_ASSERT(reporter, ds.bytesWritten() == 0); test_loop_stream(reporter, stream.get(), s, 26, 100); std::unique_ptr<SkStreamAsset> stream2(stream->duplicate()); test_loop_stream(reporter, stream2.get(), s, 26, 100); } delete[] dst; SkString tmpDir = skiatest::GetTmpDir(); if (!tmpDir.isEmpty()) { test_filestreams(reporter, tmpDir.c_str()); } }
int main(int argc, char *argv[]) { QApplication a(argc, argv); QStringList argList = a.arguments(); if (argList.count() <= 0) { return -1; // should at least have command name } SkString input; QStringList::const_iterator iter = argList.begin(); SkString commandName(iter->toAscii().data()); ++iter; // skip the command name for ( ; iter != argList.end(); ++iter) { if (0 == iter->compare("--help") || 0 == iter->compare("-h")) { usage(commandName.c_str()); return -1; } else if (input.isEmpty()) { input = SkString(iter->toAscii().data()); } else { usage(commandName.c_str()); return -1; } } SkDebuggerGUI w; if (!input.isEmpty()) { if (SkStrEndsWith(input.c_str(), ".skp")) { w.openFile(input.c_str()); } else { w.setupDirectoryWidget(input.c_str()); } } w.show(); return a.exec(); }
static bool parse_option_int(const SkString& value, int* outInt) { if (value.isEmpty()) { return false; } char* endptr = nullptr; long intValue = strtol(value.c_str(), &endptr, 10); if (*endptr != '\0') { return false; } *outInt = static_cast<int>(intValue); return true; }
void create_and_write_diff_image(DiffRecord* drp, DiffMetricProc dmp, const int colorThreshold, const SkString& outputDir, const SkString& filename) { const int w = drp->fBase.fBitmap.width(); const int h = drp->fBase.fBitmap.height(); if (w != drp->fComparison.fBitmap.width() || h != drp->fComparison.fBitmap.height()) { drp->fResult = DiffRecord::kDifferentSizes_Result; } else { drp->fDifference.fBitmap.setConfig(SkBitmap::kARGB_8888_Config, w, h); drp->fDifference.fBitmap.allocPixels(); drp->fWhite.fBitmap.setConfig(SkBitmap::kARGB_8888_Config, w, h); drp->fWhite.fBitmap.allocPixels(); SkASSERT(DiffRecord::kUnknown_Result == drp->fResult); compute_diff(drp, dmp, colorThreshold); SkASSERT(DiffRecord::kUnknown_Result != drp->fResult); } if (outputDir.isEmpty()) { drp->fDifference.fStatus = DiffResource::kUnspecified_Status; drp->fWhite.fStatus = DiffResource::kUnspecified_Status; } else { drp->fDifference.fFilename = filename_to_diff_filename(filename); drp->fDifference.fFullPath = outputDir; drp->fDifference.fFullPath.append(drp->fDifference.fFilename); drp->fDifference.fStatus = DiffResource::kSpecified_Status; drp->fWhite.fFilename = filename_to_white_filename(filename); drp->fWhite.fFullPath = outputDir; drp->fWhite.fFullPath.append(drp->fWhite.fFilename); drp->fWhite.fStatus = DiffResource::kSpecified_Status; if (DiffRecord::kDifferentPixels_Result == drp->fResult) { if (write_bitmap(drp->fDifference.fFullPath, drp->fDifference.fBitmap)) { drp->fDifference.fStatus = DiffResource::kExists_Status; } else { drp->fDifference.fStatus = DiffResource::kDoesNotExist_Status; } if (write_bitmap(drp->fWhite.fFullPath, drp->fWhite.fBitmap)) { drp->fWhite.fStatus = DiffResource::kExists_Status; } else { drp->fWhite.fStatus = DiffResource::kDoesNotExist_Status; } } } }
/// Internal (potentially recursive) implementation of get_file_list. static void get_file_list_subdir(const SkString& rootDir, const SkString& subDir, const StringArray& matchSubstrings, const StringArray& nomatchSubstrings, bool recurseIntoSubdirs, FileArray *files) { bool isSubDirEmpty = subDir.isEmpty(); SkString dir(rootDir); if (!isSubDirEmpty) { dir.append(PATH_DIV_STR); dir.append(subDir); } // Iterate over files (not directories) within dir. SkOSFile::Iter fileIterator(dir.c_str()); SkString fileName; while (fileIterator.next(&fileName, false)) { if (fileName.startsWith(".")) { continue; } SkString pathRelativeToRootDir(subDir); if (!isSubDirEmpty) { pathRelativeToRootDir.append(PATH_DIV_STR); } pathRelativeToRootDir.append(fileName); if (string_contains_any_of(pathRelativeToRootDir, matchSubstrings) && !string_contains_any_of(pathRelativeToRootDir, nomatchSubstrings)) { files->push(new SkString(pathRelativeToRootDir)); } } // Recurse into any non-ignored subdirectories. if (recurseIntoSubdirs) { SkOSFile::Iter dirIterator(dir.c_str()); SkString dirName; while (dirIterator.next(&dirName, true)) { if (dirName.startsWith(".")) { continue; } SkString pathRelativeToRootDir(subDir); if (!isSubDirEmpty) { pathRelativeToRootDir.append(PATH_DIV_STR); } pathRelativeToRootDir.append(dirName); if (!string_contains_any_of(pathRelativeToRootDir, nomatchSubstrings)) { get_file_list_subdir(rootDir, pathRelativeToRootDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, files); } } } }
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { if (NULL == stream || stream->getLength() <= 0) { return NULL; } bool isFixedWidth; SkString name; SkTypeface::Style style; find_name_and_attributes(stream, &name, &style, &isFixedWidth); if (!name.isEmpty()) { return SkNEW_ARGS(StreamTypeface, (style, false, NULL, stream, isFixedWidth)); } else { return NULL; } }
static void test_unpremul(skiatest::Reporter* reporter) { // This test cannot run if there is no resource path. SkString resourcePath = GetResourcePath(); if (resourcePath.isEmpty()) { SkDebugf("Could not run unpremul test because resourcePath not specified."); return; } SkOSFile::Iter iter(resourcePath.c_str()); SkString basename; if (iter.next(&basename)) { do { SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), basename.c_str()); // SkDebugf("about to decode \"%s\"\n", filename.c_str()); compare_unpremul(reporter, filename); } while (iter.next(&basename)); } else { SkDebugf("Failed to find any files :(\n"); } }
/** * Test SkOSPath::Join, SkOSPath::Basename, and SkOSPath::Dirname. * Will use SkOSPath::Join to append filename to dir, test that it works correctly, * and tests using SkOSPath::Basename on the result. * @param reporter Reporter for test conditions. * @param dir String representing the path to a folder. May or may not * end with SkOSPath::SEPARATOR. * @param filename String representing the basename of a file. Must NOT * contain SkOSPath::SEPARATOR. */ static void test_dir_with_file(skiatest::Reporter* reporter, SkString dir, SkString filename) { // If filename contains SkOSPath::SEPARATOR, the tests will fail. SkASSERT(!filename.contains(SkOSPath::SEPARATOR)); // Tests for SkOSPath::Join and SkOSPath::Basename // fullName should be "dir<SkOSPath::SEPARATOR>file" SkString fullName = SkOSPath::Join(dir.c_str(), filename.c_str()); // fullName should be the combined size of dir and file, plus one if // dir did not include the final path separator. size_t expectedSize = dir.size() + filename.size(); if (!dir.endsWith(SkOSPath::SEPARATOR) && !dir.isEmpty()) { expectedSize++; } REPORTER_ASSERT(reporter, fullName.size() == expectedSize); SkString basename = SkOSPath::Basename(fullName.c_str()); SkString dirname = SkOSPath::Dirname(fullName.c_str()); // basename should be the same as filename REPORTER_ASSERT(reporter, basename.equals(filename)); // dirname should be the same as dir with any trailing seperators removed. // Except when the the string is just "/". SkString strippedDir = dir; while (strippedDir.size() > 2 && strippedDir[strippedDir.size() - 1] == SkOSPath::SEPARATOR) { strippedDir.remove(strippedDir.size() - 1, 1); } if (!dirname.equals(strippedDir)) { SkDebugf("OOUCH %s %s %s\n", dir.c_str(), strippedDir.c_str(), dirname.c_str()); } REPORTER_ASSERT(reporter, dirname.equals(strippedDir)); // basename will not contain a path separator REPORTER_ASSERT(reporter, !basename.contains(SkOSPath::SEPARATOR)); // Now take the basename of filename, which should be the same as filename. basename = SkOSPath::Basename(filename.c_str()); REPORTER_ASSERT(reporter, basename.equals(filename)); }
DEF_TEST(OSPath, reporter) { SkString dir("dir"); SkString filename("file"); test_dir_with_file(reporter, dir, filename); // Now make sure this works with a path separator at the end of dir. dir.appendUnichar(SkOSPath::SEPARATOR); test_dir_with_file(reporter, dir, filename); // Test using no filename. test_dir_with_file(reporter, dir, SkString()); // Testing using no directory. test_dir_with_file(reporter, SkString(), filename); // Test with a sub directory. dir.append("subDir"); test_dir_with_file(reporter, dir, filename); // Basename of a directory with a path separator at the end is empty. dir.appendUnichar(SkOSPath::SEPARATOR); SkString baseOfDir = SkOSPath::Basename(dir.c_str()); REPORTER_ASSERT(reporter, baseOfDir.size() == 0); // Basename of nullptr is an empty string. SkString empty = SkOSPath::Basename(nullptr); REPORTER_ASSERT(reporter, empty.size() == 0); // File in root dir dir.printf("%c", SkOSPath::SEPARATOR); filename.set("file"); test_dir_with_file(reporter, dir, filename); // Just the root dir filename.reset(); test_dir_with_file(reporter, dir, filename); // Test that nullptr can be used for the directory and filename. SkString emptyPath = SkOSPath::Join(nullptr, nullptr); REPORTER_ASSERT(reporter, emptyPath.isEmpty()); }
DEF_TEST(ImageDecoding_alphaType, reporter) { SkString resourcePath = GetResourcePath(); if (resourcePath.isEmpty()) { SkDebugf("Could not run alphaType test because resourcePath not specified."); return; } SkOSFile::Iter iter(resourcePath.c_str()); SkString basename; if (iter.next(&basename)) { do { SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), basename.c_str()); for (int truth = 0; truth <= 1; ++truth) { test_alphaType(reporter, filename, SkToBool(truth)); } } while (iter.next(&basename)); } else { SkDebugf("Failed to find any files :(\n"); } }
/** Write the output of pdf renderer to a file. * @param outputDir Output dir. * @param inputFilename The skp file that was read. * @param renderer The object responsible to write the pdf file. */ static bool write_output(const SkString& outputDir, const SkString& inputFilename, const sk_tools::PdfRenderer& renderer) { if (outputDir.isEmpty()) { SkDynamicMemoryWStream stream; renderer.write(&stream); return true; } SkString outputPath; if (!make_output_filepath(&outputPath, outputDir, inputFilename)) { return false; } SkFILEWStream stream(outputPath.c_str()); if (!stream.isValid()) { SkDebugf("Could not write to file %s\n", outputPath.c_str()); return false; } renderer.write(&stream); return true; }
static void TestString(skiatest::Reporter* reporter) { SkString a; SkString b((size_t)0); SkString c(""); SkString d(NULL, 0); REPORTER_ASSERT(reporter, a.isEmpty()); REPORTER_ASSERT(reporter, a == b && a == c && a == d); a.set("hello"); b.set("hellox", 5); c.set(a); d.resize(5); memcpy(d.writable_str(), "helloz", 5); REPORTER_ASSERT(reporter, !a.isEmpty()); REPORTER_ASSERT(reporter, a.size() == 5); REPORTER_ASSERT(reporter, a == b && a == c && a == d); REPORTER_ASSERT(reporter, a.equals("hello", 5)); REPORTER_ASSERT(reporter, a.equals("hello")); REPORTER_ASSERT(reporter, !a.equals("help")); SkString e(a); SkString f("hello"); SkString g("helloz", 5); REPORTER_ASSERT(reporter, a == e && a == f && a == g); b.set("world"); c = b; REPORTER_ASSERT(reporter, a != b && a != c && b == c); a.append(" world"); e.append("worldz", 5); e.insert(5, " "); f.set("world"); f.prepend("hello "); REPORTER_ASSERT(reporter, a.equals("hello world") && a == e && a == f); a.reset(); b.resize(0); REPORTER_ASSERT(reporter, a.isEmpty() && b.isEmpty() && a == b); a.set("a"); a.set("ab"); a.set("abc"); a.set("abcd"); a.set(""); a.appendS64(72036854775808LL, 0); REPORTER_ASSERT(reporter, a.equals("72036854775808")); a.set(""); a.appendS64(-1844674407370LL, 0); REPORTER_ASSERT(reporter, a.equals("-1844674407370")); a.set(""); a.appendS64(73709551616LL, 15); REPORTER_ASSERT(reporter, a.equals("000073709551616")); a.set(""); a.appendS64(-429496729612LL, 15); REPORTER_ASSERT(reporter, a.equals("-000429496729612")); }
static void Run(Task* task) { SkString name = task->src->name(); // We'll skip drawing this Src/Sink pair if: // - the Src vetoes the Sink; // - this Src / Sink combination is on the blacklist; // - it's a dry run. SkString note(task->src->veto(task->sink->flags()) ? " (veto)" : ""); SkString whyBlacklisted = is_blacklisted(task->sink.tag, task->src.tag, task->src.options, name.c_str()); if (!whyBlacklisted.isEmpty()) { note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); } SkString log; WallTimer timer; timer.start(); if (!FLAGS_dryRun && note.isEmpty()) { SkBitmap bitmap; SkDynamicMemoryWStream stream; if (FLAGS_pre_log) { SkDebugf("\nRunning %s->%s", name.c_str(), task->sink.tag); } start(task->sink.tag, task->src.tag, task->src.options, name.c_str()); Error err = task->sink->draw(*task->src, &bitmap, &stream, &log); if (!err.isEmpty()) { timer.end(); if (err.isFatal()) { fail(SkStringPrintf("%s %s %s %s: %s", task->sink.tag, task->src.tag, task->src.options, name.c_str(), err.c_str())); } else { note.appendf(" (skipped: %s)", err.c_str()); } done(timer.fWall, task->sink.tag, task->src.tag, task->src.options, name, note, log); return; } SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream()); SkString md5; if (!FLAGS_writePath.isEmpty() || !FLAGS_readPath.isEmpty()) { SkMD5 hash; if (data->getLength()) { hash.writeStream(data, data->getLength()); data->rewind(); } else { // If we're BGRA (Linux, Windows), swizzle over to RGBA (Mac, Android). // This helps eliminate multiple 0-pixel-diff hashes on gold.skia.org. // (Android's general slow speed breaks the tie arbitrarily in RGBA's favor.) // We might consider promoting 565 to RGBA too. if (bitmap.colorType() == kBGRA_8888_SkColorType) { SkBitmap swizzle; SkAssertResult(bitmap.copyTo(&swizzle, kRGBA_8888_SkColorType)); hash.write(swizzle.getPixels(), swizzle.getSize()); } else { hash.write(bitmap.getPixels(), bitmap.getSize()); } } SkMD5::Digest digest; hash.finish(digest); for (int i = 0; i < 16; i++) { md5.appendf("%02x", digest.data[i]); } } if (!FLAGS_readPath.isEmpty() && !gGold.contains(Gold(task->sink.tag, task->src.tag, task->src.options, name, md5))) { fail(SkStringPrintf("%s not found for %s %s %s %s in %s", md5.c_str(), task->sink.tag, task->src.tag, task->src.options, name.c_str(), FLAGS_readPath[0])); } if (!FLAGS_writePath.isEmpty()) { const char* ext = task->sink->fileExtension(); if (data->getLength()) { WriteToDisk(*task, md5, ext, data, data->getLength(), nullptr); SkASSERT(bitmap.drawsNothing()); } else if (!bitmap.drawsNothing()) { WriteToDisk(*task, md5, ext, nullptr, 0, &bitmap); } } } timer.end(); done(timer.fWall, task->sink.tag, task->src.tag, task->src.options, name, note, log); }
int test_main() { SetupCrashHandler(); SkAutoGraphics ag; { SkString header("Skia UnitTests:"); if (!FLAGS_match.isEmpty()) { header.appendf(" --match"); for (int index = 0; index < FLAGS_match.count(); ++index) { header.appendf(" %s", FLAGS_match[index]); } } SkString tmpDir = skiatest::GetTmpDir(); if (!tmpDir.isEmpty()) { header.appendf(" --tmpDir %s", tmpDir.c_str()); } SkString resourcePath = GetResourcePath(); if (!resourcePath.isEmpty()) { header.appendf(" --resourcePath %s", resourcePath.c_str()); } #ifdef SK_DEBUG header.append(" SK_DEBUG"); #else header.append(" SK_RELEASE"); #endif if (FLAGS_veryVerbose) { header.appendf("\n"); } SkDebugf("%s", header.c_str()); } // Count tests first. int total = 0; int toRun = 0; for (const TestRegistry* iter = TestRegistry::Head(); iter; iter = iter->next()) { const Test& test = iter->factory(); if (should_run(test.name, test.needsGpu)) { toRun++; } total++; } // Now run them. int skipCount = 0; SkTaskGroup::Enabler enabled(FLAGS_threads); SkTaskGroup cpuTests; SkTArray<const Test*> gpuTests; Status status(toRun); for (const TestRegistry* iter = TestRegistry::Head(); iter; iter = iter->next()) { const Test& test = iter->factory(); if (!should_run(test.name, test.needsGpu)) { ++skipCount; } else if (test.needsGpu) { gpuTests.push_back(&test); } else { cpuTests.add(new SkTestRunnable(test, &status)); } } GrContextFactory* grContextFactoryPtr = NULL; #if SK_SUPPORT_GPU // Give GPU tests a context factory if that makes sense on this machine. GrContextFactory grContextFactory; grContextFactoryPtr = &grContextFactory; #endif // Run GPU tests on this thread. for (int i = 0; i < gpuTests.count(); i++) { (new SkTestRunnable(*gpuTests[i], &status, grContextFactoryPtr))->run(); } // Block until threaded tests finish. cpuTests.wait(); if (FLAGS_verbose) { SkDebugf( "\nFinished %d tests, %d failures, %d skipped. " "(%d internal tests)", toRun, status.failCount(), skipCount, status.testCount()); } SkDebugf("\n"); return (status.failCount() == 0) ? 0 : 1; }
void SkDiffContext::setWhiteDiffDir(const SkString& path) { if (!path.isEmpty() && sk_mkdir(path.c_str())) { fWhiteDiffDir = path; } }
void SkDiffContext::setAlphaMaskDir(const SkString& path) { if (!path.isEmpty() && sk_mkdir(path.c_str())) { fAlphaMaskDir = path; } }
/// Creates difference images, returns the number that have a 0 metric. /// If outputDir.isEmpty(), don't write out diff files. static void create_diff_images (DiffMetricProc dmp, const int colorThreshold, RecordArray* differences, const SkString& baseDir, const SkString& comparisonDir, const SkString& outputDir, const StringArray& matchSubstrings, const StringArray& nomatchSubstrings, bool recurseIntoSubdirs, bool getBounds, bool verbose, DiffSummary* summary) { SkASSERT(!baseDir.isEmpty()); SkASSERT(!comparisonDir.isEmpty()); FileArray baseFiles; FileArray comparisonFiles; get_file_list(baseDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, &baseFiles); get_file_list(comparisonDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, &comparisonFiles); if (!baseFiles.isEmpty()) { qsort(baseFiles.begin(), baseFiles.count(), sizeof(SkString*), SkCastForQSort(compare_file_name_metrics)); } if (!comparisonFiles.isEmpty()) { qsort(comparisonFiles.begin(), comparisonFiles.count(), sizeof(SkString*), SkCastForQSort(compare_file_name_metrics)); } int i = 0; int j = 0; while (i < baseFiles.count() && j < comparisonFiles.count()) { SkString basePath(baseDir); SkString comparisonPath(comparisonDir); DiffRecord *drp = new DiffRecord; int v = strcmp(baseFiles[i]->c_str(), comparisonFiles[j]->c_str()); if (v < 0) { // in baseDir, but not in comparisonDir drp->fResult = DiffRecord::kCouldNotCompare_Result; basePath.append(*baseFiles[i]); comparisonPath.append(*baseFiles[i]); drp->fBase.fFilename = *baseFiles[i]; drp->fBase.fFullPath = basePath; drp->fBase.fStatus = DiffResource::kExists_Status; drp->fComparison.fFilename = *baseFiles[i]; drp->fComparison.fFullPath = comparisonPath; drp->fComparison.fStatus = DiffResource::kDoesNotExist_Status; VERBOSE_STATUS("MISSING", ANSI_COLOR_YELLOW, baseFiles[i]); ++i; } else if (v > 0) { // in comparisonDir, but not in baseDir drp->fResult = DiffRecord::kCouldNotCompare_Result; basePath.append(*comparisonFiles[j]); comparisonPath.append(*comparisonFiles[j]); drp->fBase.fFilename = *comparisonFiles[j]; drp->fBase.fFullPath = basePath; drp->fBase.fStatus = DiffResource::kDoesNotExist_Status; drp->fComparison.fFilename = *comparisonFiles[j]; drp->fComparison.fFullPath = comparisonPath; drp->fComparison.fStatus = DiffResource::kExists_Status; VERBOSE_STATUS("MISSING", ANSI_COLOR_YELLOW, comparisonFiles[j]); ++j; } else { // Found the same filename in both baseDir and comparisonDir. SkASSERT(DiffRecord::kUnknown_Result == drp->fResult); basePath.append(*baseFiles[i]); comparisonPath.append(*comparisonFiles[j]); drp->fBase.fFilename = *baseFiles[i]; drp->fBase.fFullPath = basePath; drp->fBase.fStatus = DiffResource::kExists_Status; drp->fComparison.fFilename = *comparisonFiles[j]; drp->fComparison.fFullPath = comparisonPath; drp->fComparison.fStatus = DiffResource::kExists_Status; SkAutoDataUnref baseFileBits(read_file(drp->fBase.fFullPath.c_str())); if (baseFileBits) { drp->fBase.fStatus = DiffResource::kRead_Status; } SkAutoDataUnref comparisonFileBits(read_file(drp->fComparison.fFullPath.c_str())); if (comparisonFileBits) { drp->fComparison.fStatus = DiffResource::kRead_Status; } if (NULL == baseFileBits || NULL == comparisonFileBits) { if (NULL == baseFileBits) { drp->fBase.fStatus = DiffResource::kCouldNotRead_Status; VERBOSE_STATUS("READ FAIL", ANSI_COLOR_RED, baseFiles[i]); } if (NULL == comparisonFileBits) { drp->fComparison.fStatus = DiffResource::kCouldNotRead_Status; VERBOSE_STATUS("READ FAIL", ANSI_COLOR_RED, comparisonFiles[j]); } drp->fResult = DiffRecord::kCouldNotCompare_Result; } else if (are_buffers_equal(baseFileBits, comparisonFileBits)) { drp->fResult = DiffRecord::kEqualBits_Result; VERBOSE_STATUS("MATCH", ANSI_COLOR_GREEN, baseFiles[i]); } else { AutoReleasePixels arp(drp); get_bitmap(baseFileBits, drp->fBase, SkImageDecoder::kDecodePixels_Mode); get_bitmap(comparisonFileBits, drp->fComparison, SkImageDecoder::kDecodePixels_Mode); VERBOSE_STATUS("DIFFERENT", ANSI_COLOR_RED, baseFiles[i]); if (DiffResource::kDecoded_Status == drp->fBase.fStatus && DiffResource::kDecoded_Status == drp->fComparison.fStatus) { create_and_write_diff_image(drp, dmp, colorThreshold, outputDir, drp->fBase.fFilename); } else { drp->fResult = DiffRecord::kCouldNotCompare_Result; } } ++i; ++j; } if (getBounds) { get_bounds(*drp); } SkASSERT(DiffRecord::kUnknown_Result != drp->fResult); differences->push(drp); summary->add(drp); } for (; i < baseFiles.count(); ++i) { // files only in baseDir DiffRecord *drp = new DiffRecord(); drp->fBase.fFilename = *baseFiles[i]; drp->fBase.fFullPath = baseDir; drp->fBase.fFullPath.append(drp->fBase.fFilename); drp->fBase.fStatus = DiffResource::kExists_Status; drp->fComparison.fFilename = *baseFiles[i]; drp->fComparison.fFullPath = comparisonDir; drp->fComparison.fFullPath.append(drp->fComparison.fFilename); drp->fComparison.fStatus = DiffResource::kDoesNotExist_Status; drp->fResult = DiffRecord::kCouldNotCompare_Result; if (getBounds) { get_bounds(*drp); } differences->push(drp); summary->add(drp); } for (; j < comparisonFiles.count(); ++j) { // files only in comparisonDir DiffRecord *drp = new DiffRecord(); drp->fBase.fFilename = *comparisonFiles[j]; drp->fBase.fFullPath = baseDir; drp->fBase.fFullPath.append(drp->fBase.fFilename); drp->fBase.fStatus = DiffResource::kDoesNotExist_Status; drp->fComparison.fFilename = *comparisonFiles[j]; drp->fComparison.fFullPath = comparisonDir; drp->fComparison.fFullPath.append(drp->fComparison.fFilename); drp->fComparison.fStatus = DiffResource::kExists_Status; drp->fResult = DiffRecord::kCouldNotCompare_Result; if (getBounds) { get_bounds(*drp); } differences->push(drp); summary->add(drp); } release_file_list(&baseFiles); release_file_list(&comparisonFiles); }
/** * Write the canvas to an image file and/or JSON summary. * * @param canvas Must be non-null. Canvas to be written to a file. * @param writePath If nonempty, write the binary image to a file within this directory. * @param mismatchPath If nonempty, write the binary image to a file within this directory, * but only if the image does not match expectations. * @param inputFilename If we are writing out a binary image, use this to build its filename. * @param jsonSummaryPtr If not null, add image results (checksum) to this summary. * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk. * @param tileNumberPtr If not null, which tile number this image contains. * * @return bool True if the operation completed successfully. */ static bool write(SkCanvas* canvas, const SkString& writePath, const SkString& mismatchPath, const SkString& inputFilename, ImageResultsAndExpectations *jsonSummaryPtr, bool useChecksumBasedFilenames, const int* tileNumberPtr=NULL) { SkASSERT(canvas != NULL); if (NULL == canvas) { return false; } SkBitmap bitmap; SkISize size = canvas->getDeviceSize(); setup_bitmap(&bitmap, size.width(), size.height()); canvas->readPixels(&bitmap, 0, 0); force_all_opaque(bitmap); BitmapAndDigest bitmapAndDigest(bitmap); SkString escapedInputFilename(inputFilename); replace_char(&escapedInputFilename, '.', '_'); // TODO(epoger): what about including the config type within outputFilename? That way, // we could combine results of different config types without conflicting filenames. SkString outputFilename; const char *outputSubdirPtr = NULL; if (useChecksumBasedFilenames) { ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr(); outputSubdirPtr = escapedInputFilename.c_str(); outputFilename.set(imageDigestPtr->getHashType()); outputFilename.append("_"); outputFilename.appendU64(imageDigestPtr->getHashValue()); } else { outputFilename.set(escapedInputFilename); if (tileNumberPtr) { outputFilename.append("-tile"); outputFilename.appendS32(*tileNumberPtr); } } outputFilename.append(".png"); if (jsonSummaryPtr) { ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr(); SkString outputRelativePath; if (outputSubdirPtr) { outputRelativePath.set(outputSubdirPtr); outputRelativePath.append("/"); // always use "/", even on Windows outputRelativePath.append(outputFilename); } else { outputRelativePath.set(outputFilename); } jsonSummaryPtr->add(inputFilename.c_str(), outputRelativePath.c_str(), *imageDigestPtr, tileNumberPtr); if (!mismatchPath.isEmpty() && !jsonSummaryPtr->getExpectation(inputFilename.c_str(), tileNumberPtr).matches(*imageDigestPtr)) { if (!write_bitmap_to_disk(bitmap, mismatchPath, outputSubdirPtr, outputFilename)) { return false; } } } if (writePath.isEmpty()) { return true; } else { return write_bitmap_to_disk(bitmap, writePath, outputSubdirPtr, outputFilename); } }