Flutter Engine
The Flutter Engine
Classes | Macros | Typedefs | Functions | Variables
skdiff_main.cpp File Reference
#include "include/core/SkBitmap.h"
#include "include/core/SkData.h"
#include "include/core/SkPixelRef.h"
#include "include/core/SkStream.h"
#include "include/private/base/SkTDArray.h"
#include "src/base/SkTSearch.h"
#include "src/core/SkOSFile.h"
#include "src/utils/SkOSPath.h"
#include "tools/skdiff/skdiff.h"
#include "tools/skdiff/skdiff_html.h"
#include "tools/skdiff/skdiff_utils.h"
#include <stdlib.h>

Go to the source code of this file.

Classes

struct  DiffSummary
 
class  AutoReleasePixels
 

Macros

#define ANSI_COLOR_RED   "\x1b[31m"
 
#define ANSI_COLOR_GREEN   "\x1b[32m"
 
#define ANSI_COLOR_YELLOW   "\x1b[33m"
 
#define ANSI_COLOR_RESET   "\x1b[0m"
 
#define VERBOSE_STATUS(status, color, filename)   if (verbose) printf( "[ " color " %10s " ANSI_COLOR_RESET " ] %s\n", status, filename.c_str())
 

Typedefs

typedef TArray< SkStringStringArray
 
typedef StringArray FileArray
 

Functions

static void add_unique_basename (StringArray *array, const SkString &filename)
 
static bool string_contains_any_of (const SkString &string, const StringArray &substrings)
 Returns true if string contains any of these substrings. More...
 
static void get_file_list_subdir (const SkString &rootDir, const SkString &subDir, const StringArray &matchSubstrings, const StringArray &nomatchSubstrings, bool recurseIntoSubdirs, FileArray *files)
 Internal (potentially recursive) implementation of get_file_list. More...
 
static void get_file_list (const SkString &dir, const StringArray &matchSubstrings, const StringArray &nomatchSubstrings, bool recurseIntoSubdirs, FileArray *files)
 
static int compare_file_name_metrics (SkString *lhs, SkString *rhs)
 Comparison routines for qsort, sort by file names. More...
 
static void get_bounds (DiffResource &resource, const char *name)
 
static void get_bounds (DiffRecord &drp)
 
static void create_diff_images (DiffMetricProc dmp, const int colorThreshold, bool ignoreColorSpace, 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)
 
static void usage (char *argv0)
 
int main (int argc, char **argv)
 

Variables

const int kNoError = 0
 
const int kGenericError = -1
 

Macro Definition Documentation

◆ ANSI_COLOR_GREEN

#define ANSI_COLOR_GREEN   "\x1b[32m"

Definition at line 353 of file skdiff_main.cpp.

◆ ANSI_COLOR_RED

#define ANSI_COLOR_RED   "\x1b[31m"

Definition at line 352 of file skdiff_main.cpp.

◆ ANSI_COLOR_RESET

#define ANSI_COLOR_RESET   "\x1b[0m"

Definition at line 355 of file skdiff_main.cpp.

◆ ANSI_COLOR_YELLOW

#define ANSI_COLOR_YELLOW   "\x1b[33m"

Definition at line 354 of file skdiff_main.cpp.

◆ VERBOSE_STATUS

#define VERBOSE_STATUS (   status,
  color,
  filename 
)    if (verbose) printf( "[ " color " %10s " ANSI_COLOR_RESET " ] %s\n", status, filename.c_str())

Definition at line 358 of file skdiff_main.cpp.

Typedef Documentation

◆ FileArray

Definition at line 38 of file skdiff_main.cpp.

◆ StringArray

skdiff

Given three directory names, expects to find identically-named files in each of the first two; the first are treated as a set of baseline, the second a set of variant images, and a diff image is written into the third directory for each pair. Creates an index.html in the current third directory to compare each pair that does not match exactly. Recursively descends directories, unless run with –norecurse.

Returns zero exit code if all images match across baseDir and comparisonDir.

Definition at line 37 of file skdiff_main.cpp.

Function Documentation

◆ add_unique_basename()

static void add_unique_basename ( StringArray array,
const SkString filename 
)
static

Definition at line 40 of file skdiff_main.cpp.

40 {
41 // trim off dirs
42 const char* src = filename.c_str();
43 const char* trimmed = strrchr(src, SkOSPath::SEPARATOR);
44 if (trimmed) {
45 trimmed += 1; // skip the separator
46 } else {
47 trimmed = src;
48 }
49 const char* end = strrchr(trimmed, '.');
50 if (!end) {
51 end = trimmed + strlen(trimmed);
52 }
53 SkString result(trimmed, end - trimmed);
54
55 // only add unique entries
56 for (int i = 0; i < array->size(); ++i) {
57 if (array->at(i) == result) {
58 return;
59 }
60 }
61 array->push_back(std::move(result));
62}
static constexpr char SEPARATOR
Definition: SkOSPath.h:21
const char * c_str() const
Definition: SkString.h:133
int size() const
Definition: SkTArray.h:421
glong glong end
GAsyncResult * result

◆ compare_file_name_metrics()

static int compare_file_name_metrics ( SkString lhs,
SkString rhs 
)
static

Comparison routines for qsort, sort by file names.

Definition at line 308 of file skdiff_main.cpp.

308 {
309 return strcmp(lhs->c_str(), rhs->c_str());
310}

◆ create_diff_images()

static void create_diff_images ( DiffMetricProc  dmp,
const int  colorThreshold,
bool  ignoreColorSpace,
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 
)
static

Creates difference images, returns the number that have a 0 metric. If outputDir.isEmpty(), don't write out diff files.

Definition at line 362 of file skdiff_main.cpp.

374 {
375 SkASSERT(!baseDir.isEmpty());
376 SkASSERT(!comparisonDir.isEmpty());
377
378 FileArray baseFiles;
379 FileArray comparisonFiles;
380
381 get_file_list(baseDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, &baseFiles);
382 get_file_list(comparisonDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs,
383 &comparisonFiles);
384
385 if (!baseFiles.empty()) {
386 qsort(baseFiles.begin(), baseFiles.size(), sizeof(SkString),
388 }
389 if (!comparisonFiles.empty()) {
390 qsort(comparisonFiles.begin(), comparisonFiles.size(), sizeof(SkString),
392 }
393
394 if (!outputDir.isEmpty()) {
395 sk_mkdir(outputDir.c_str());
396 }
397
398 int i = 0;
399 int j = 0;
400
401 while (i < baseFiles.size() &&
402 j < comparisonFiles.size()) {
403
404 SkString basePath(baseDir);
405 SkString comparisonPath(comparisonDir);
406
407 DiffRecord drp;
408 int v = strcmp(baseFiles[i].c_str(), comparisonFiles[j].c_str());
409
410 if (v < 0) {
411 // in baseDir, but not in comparisonDir
413
414 basePath.append(baseFiles[i]);
415 comparisonPath.append(baseFiles[i]);
416
417 drp.fBase.fFilename = baseFiles[i];
418 drp.fBase.fFullPath = basePath;
420
421 drp.fComparison.fFilename = baseFiles[i];
422 drp.fComparison.fFullPath = comparisonPath;
424
425 VERBOSE_STATUS("MISSING", ANSI_COLOR_YELLOW, baseFiles[i]);
426
427 ++i;
428 } else if (v > 0) {
429 // in comparisonDir, but not in baseDir
431
432 basePath.append(comparisonFiles[j]);
433 comparisonPath.append(comparisonFiles[j]);
434
435 drp.fBase.fFilename = comparisonFiles[j];
436 drp.fBase.fFullPath = basePath;
438
439 drp.fComparison.fFilename = comparisonFiles[j];
440 drp.fComparison.fFullPath = comparisonPath;
442
443 VERBOSE_STATUS("MISSING", ANSI_COLOR_YELLOW, comparisonFiles[j]);
444
445 ++j;
446 } else {
447 // Found the same filename in both baseDir and comparisonDir.
449
450 basePath.append(baseFiles[i]);
451 comparisonPath.append(comparisonFiles[j]);
452
453 drp.fBase.fFilename = baseFiles[i];
454 drp.fBase.fFullPath = basePath;
456
457 drp.fComparison.fFilename = comparisonFiles[j];
458 drp.fComparison.fFullPath = comparisonPath;
460
461 sk_sp<SkData> baseFileBits(read_file(drp.fBase.fFullPath.c_str()));
462 if (baseFileBits) {
464 }
465 sk_sp<SkData> comparisonFileBits(read_file(drp.fComparison.fFullPath.c_str()));
466 if (comparisonFileBits) {
468 }
469 if (nullptr == baseFileBits || nullptr == comparisonFileBits) {
470 if (nullptr == baseFileBits) {
472 VERBOSE_STATUS("READ FAIL", ANSI_COLOR_RED, baseFiles[i]);
473 }
474 if (nullptr == comparisonFileBits) {
476 VERBOSE_STATUS("READ FAIL", ANSI_COLOR_RED, comparisonFiles[j]);
477 }
479
480 } else if (are_buffers_equal(baseFileBits.get(), comparisonFileBits.get())) {
482 VERBOSE_STATUS("MATCH", ANSI_COLOR_GREEN, baseFiles[i]);
483 } else {
484 AutoReleasePixels arp(&drp);
485 get_bitmap(baseFileBits, drp.fBase, false, ignoreColorSpace);
486 get_bitmap(comparisonFileBits, drp.fComparison, false, ignoreColorSpace);
487 VERBOSE_STATUS("DIFFERENT", ANSI_COLOR_RED, baseFiles[i]);
490 create_and_write_diff_image(&drp, dmp, colorThreshold,
491 outputDir, drp.fBase.fFilename);
492 } else {
494 }
495 }
496
497 ++i;
498 ++j;
499 }
500
501 if (getBounds) {
502 get_bounds(drp);
503 }
505 summary->add(drp);
506 differences->push_back(std::move(drp));
507 }
508
509 for (; i < baseFiles.size(); ++i) {
510 // files only in baseDir
511 DiffRecord drp;
512 drp.fBase.fFilename = baseFiles[i];
513 drp.fBase.fFullPath = baseDir;
516
517 drp.fComparison.fFilename = baseFiles[i];
518 drp.fComparison.fFullPath = comparisonDir;
521
523 if (getBounds) {
524 get_bounds(drp);
525 }
526 summary->add(drp);
527 differences->push_back(std::move(drp));
528 }
529
530 for (; j < comparisonFiles.size(); ++j) {
531 // files only in comparisonDir
532 DiffRecord drp;
533 drp.fBase.fFilename = comparisonFiles[j];
534 drp.fBase.fFullPath = baseDir;
537
538 drp.fComparison.fFilename = comparisonFiles[j];
539 drp.fComparison.fFullPath = comparisonDir;
542
544 if (getBounds) {
545 get_bounds(drp);
546 }
547 summary->add(drp);
548 differences->push_back(std::move(drp));
549 }
550}
#define SkASSERT(cond)
Definition: SkAssert.h:116
bool sk_mkdir(const char *path)
#define SkCastForQSort(compare)
Definition: SkTSearch.h:130
bool isEmpty() const
Definition: SkString.h:130
void append(const char text[])
Definition: SkString.h:203
bool empty() const
Definition: SkTArray.h:199
#define VERBOSE_STATUS(status, color, filename)
#define ANSI_COLOR_RED
#define ANSI_COLOR_YELLOW
static int compare_file_name_metrics(SkString *lhs, SkString *rhs)
Comparison routines for qsort, sort by file names.
#define ANSI_COLOR_GREEN
static void get_bounds(DiffResource &resource, const char *name)
static void get_file_list(const SkString &dir, const StringArray &matchSubstrings, const StringArray &nomatchSubstrings, bool recurseIntoSubdirs, FileArray *files)
bool are_buffers_equal(SkData *skdata1, SkData *skdata2)
void create_and_write_diff_image(DiffRecord *drp, DiffMetricProc dmp, const int colorThreshold, const SkString &outputDir, const SkString &filename)
sk_sp< SkData > read_file(const char *file_path)
bool get_bitmap(sk_sp< SkData > fileBits, DiffResource &resource, bool sizeOnly, bool ignoreColorSpace)
DiffResource fComparison
Definition: skdiff.h:131
Result fResult
Which category of diff result.
Definition: skdiff.h:154
@ kUnknown_Result
Definition: skdiff.h:97
@ kEqualBits_Result
Definition: skdiff.h:92
@ kCouldNotCompare_Result
Definition: skdiff.h:96
DiffResource fBase
Definition: skdiff.h:130
SkString fFullPath
Definition: skdiff.h:81
@ kRead_Status
Definition: skdiff.h:37
@ kExists_Status
Definition: skdiff.h:42
@ kCouldNotRead_Status
Definition: skdiff.h:39
@ kDoesNotExist_Status
Definition: skdiff.h:44
@ kDecoded_Status
Definition: skdiff.h:32
Status fStatus
Definition: skdiff.h:84
SkString fFilename
Definition: skdiff.h:79
void add(const DiffRecord &drp)

◆ get_bounds() [1/2]

static void get_bounds ( DiffRecord drp)
static

Definition at line 341 of file skdiff_main.cpp.

341 {
342 get_bounds(drp.fBase, "base");
343 get_bounds(drp.fComparison, "comparison");
344}

◆ get_bounds() [2/2]

static void get_bounds ( DiffResource resource,
const char *  name 
)
static

Definition at line 329 of file skdiff_main.cpp.

329 {
330 if (resource.fBitmap.empty() && !DiffResource::isStatusFailed(resource.fStatus)) {
331 sk_sp<SkData> fileBits(read_file(resource.fFullPath.c_str()));
332 if (fileBits) {
333 get_bitmap(fileBits, resource, true, true);
334 } else {
335 SkDebugf("WARNING: couldn't read %s file <%s>\n", name, resource.fFullPath.c_str());
337 }
338 }
339}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static SkString resource(SkPDFResourceType type, int index)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
static bool isStatusFailed(Status status)
Definition: skdiff.cpp:90

◆ get_file_list()

static void get_file_list ( const SkString dir,
const StringArray matchSubstrings,
const StringArray nomatchSubstrings,
bool  recurseIntoSubdirs,
FileArray files 
)
static

Iterate over dir and get all files whose filename:

  • matches any of the substrings in matchSubstrings, but...
  • DOES NOT match any of the substrings in nomatchSubstrings
  • DOES NOT start with a dot (.) Adds the matching files to the list in *files.

Definition at line 298 of file skdiff_main.cpp.

301 {
303 matchSubstrings, nomatchSubstrings, recurseIntoSubdirs,
304 files);
305}
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
static void get_file_list_subdir(const SkString &rootDir, const SkString &subDir, const StringArray &matchSubstrings, const StringArray &nomatchSubstrings, bool recurseIntoSubdirs, FileArray *files)
Internal (potentially recursive) implementation of get_file_list.

◆ get_file_list_subdir()

static void get_file_list_subdir ( const SkString rootDir,
const SkString subDir,
const StringArray matchSubstrings,
const StringArray nomatchSubstrings,
bool  recurseIntoSubdirs,
FileArray files 
)
static

Internal (potentially recursive) implementation of get_file_list.

Definition at line 242 of file skdiff_main.cpp.

245 {
246 bool isSubDirEmpty = subDir.isEmpty();
247 SkString dir(rootDir);
248 if (!isSubDirEmpty) {
249 dir.append(PATH_DIV_STR);
250 dir.append(subDir);
251 }
252
253 // Iterate over files (not directories) within dir.
254 SkOSFile::Iter fileIterator(dir.c_str());
255 SkString fileName;
256 while (fileIterator.next(&fileName, false)) {
257 if (fileName.startsWith(".")) {
258 continue;
259 }
260 SkString pathRelativeToRootDir(subDir);
261 if (!isSubDirEmpty) {
262 pathRelativeToRootDir.append(PATH_DIV_STR);
263 }
264 pathRelativeToRootDir.append(fileName);
265 if (string_contains_any_of(pathRelativeToRootDir, matchSubstrings) &&
266 !string_contains_any_of(pathRelativeToRootDir, nomatchSubstrings)) {
267 files->push_back(std::move(pathRelativeToRootDir));
268 }
269 }
270
271 // Recurse into any non-ignored subdirectories.
272 if (recurseIntoSubdirs) {
273 SkOSFile::Iter dirIterator(dir.c_str());
274 SkString dirName;
275 while (dirIterator.next(&dirName, true)) {
276 if (dirName.startsWith(".")) {
277 continue;
278 }
279 SkString pathRelativeToRootDir(subDir);
280 if (!isSubDirEmpty) {
281 pathRelativeToRootDir.append(PATH_DIV_STR);
282 }
283 pathRelativeToRootDir.append(dirName);
284 if (!string_contains_any_of(pathRelativeToRootDir, nomatchSubstrings)) {
285 get_file_list_subdir(rootDir, pathRelativeToRootDir,
286 matchSubstrings, nomatchSubstrings, recurseIntoSubdirs,
287 files);
288 }
289 }
290 }
291}
bool startsWith(const char prefixStr[]) const
Definition: SkString.h:140
#define PATH_DIV_STR
Definition: skdiff.h:21
static bool string_contains_any_of(const SkString &string, const StringArray &substrings)
Returns true if string contains any of these substrings.

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 598 of file skdiff_main.cpp.

598 {
600 int (*sortProc)(const void*, const void*) = compare<CompareDiffMetrics>;
601
602 // Maximum error tolerated in any one color channel in any one pixel before
603 // a difference is reported.
604 int colorThreshold = 0;
605 SkString baseDir;
606 SkString comparisonDir;
607 SkString outputDir;
608
609 StringArray matchSubstrings;
610 StringArray nomatchSubstrings;
611
612 bool generateDiffs = true;
613 bool listFilenames = false;
614 bool printDirNames = true;
615 bool recurseIntoSubdirs = true;
616 bool verbose = false;
617 bool listFailingBase = false;
618 bool ignoreColorSpace = false;
619
620 RecordArray differences;
621 DiffSummary summary;
622
623 bool failOnResultType[DiffRecord::kResultCount];
624 for (int i = 0; i < DiffRecord::kResultCount; i++) {
625 failOnResultType[i] = false;
626 }
627
629 for (int base = 0; base < DiffResource::kStatusCount; ++base) {
630 for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
631 failOnStatusType[base][comparison] = false;
632 }
633 }
634
635 int numUnflaggedArguments = 0;
636 for (int i = 1; i < argc; i++) {
637 if (!strcmp(argv[i], "--failonresult")) {
638 if (argc == ++i) {
639 SkDebugf("failonresult expects one argument.\n");
640 continue;
641 }
644 failOnResultType[type] = true;
645 } else {
646 SkDebugf("ignoring unrecognized result <%s>\n", argv[i]);
647 }
648 continue;
649 }
650 if (!strcmp(argv[i], "--failonstatus")) {
651 if (argc == ++i) {
652 SkDebugf("failonstatus missing base status.\n");
653 continue;
654 }
655 bool baseStatuses[DiffResource::kStatusCount];
656 if (!DiffResource::getMatchingStatuses(argv[i], baseStatuses)) {
657 SkDebugf("unrecognized base status <%s>\n", argv[i]);
658 }
659
660 if (argc == ++i) {
661 SkDebugf("failonstatus missing comparison status.\n");
662 continue;
663 }
664 bool comparisonStatuses[DiffResource::kStatusCount];
665 if (!DiffResource::getMatchingStatuses(argv[i], comparisonStatuses)) {
666 SkDebugf("unrecognized comarison status <%s>\n", argv[i]);
667 }
668
669 for (int base = 0; base < DiffResource::kStatusCount; ++base) {
670 for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
671 failOnStatusType[base][comparison] |=
672 baseStatuses[base] && comparisonStatuses[comparison];
673 }
674 }
675 continue;
676 }
677 if (!strcmp(argv[i], "--help")) {
678 usage(argv[0]);
679 return kNoError;
680 }
681 if (!strcmp(argv[i], "--listfilenames")) {
682 listFilenames = true;
683 continue;
684 }
685 if (!strcmp(argv[i], "--verbose")) {
686 verbose = true;
687 continue;
688 }
689 if (!strcmp(argv[i], "--match")) {
690 matchSubstrings.emplace_back(argv[++i]);
691 continue;
692 }
693 if (!strcmp(argv[i], "--nocolorspace")) {
694 ignoreColorSpace = true;
695 continue;
696 }
697 if (!strcmp(argv[i], "--nodiffs")) {
698 generateDiffs = false;
699 continue;
700 }
701 if (!strcmp(argv[i], "--nomatch")) {
702 nomatchSubstrings.emplace_back(argv[++i]);
703 continue;
704 }
705 if (!strcmp(argv[i], "--noprintdirs")) {
706 printDirNames = false;
707 continue;
708 }
709 if (!strcmp(argv[i], "--norecurse")) {
710 recurseIntoSubdirs = false;
711 continue;
712 }
713 if (!strcmp(argv[i], "--sortbymaxmismatch")) {
714 sortProc = compare<CompareDiffMaxMismatches>;
715 continue;
716 }
717 if (!strcmp(argv[i], "--sortbymismatch")) {
718 sortProc = compare<CompareDiffMeanMismatches>;
719 continue;
720 }
721 if (!strcmp(argv[i], "--threshold")) {
722 colorThreshold = atoi(argv[++i]);
723 continue;
724 }
725 if (!strcmp(argv[i], "--weighted")) {
726 sortProc = compare<CompareDiffWeighted>;
727 continue;
728 }
729 if (argv[i][0] != '-') {
730 switch (numUnflaggedArguments++) {
731 case 0:
732 baseDir.set(argv[i]);
733 continue;
734 case 1:
735 comparisonDir.set(argv[i]);
736 continue;
737 case 2:
738 outputDir.set(argv[i]);
739 continue;
740 default:
741 SkDebugf("extra unflagged argument <%s>\n", argv[i]);
742 usage(argv[0]);
743 return kGenericError;
744 }
745 }
746 if (!strcmp(argv[i], "--listFailingBase")) {
747 listFailingBase = true;
748 continue;
749 }
750
751 SkDebugf("Unrecognized argument <%s>\n", argv[i]);
752 usage(argv[0]);
753 return kGenericError;
754 }
755
756 if (numUnflaggedArguments == 2) {
757 outputDir = comparisonDir;
758 } else if (numUnflaggedArguments != 3) {
759 usage(argv[0]);
760 return kGenericError;
761 }
762
763 if (!baseDir.endsWith(PATH_DIV_STR)) {
764 baseDir.append(PATH_DIV_STR);
765 }
766 if (printDirNames) {
767 printf("baseDir is [%s]\n", baseDir.c_str());
768 }
769
770 if (!comparisonDir.endsWith(PATH_DIV_STR)) {
771 comparisonDir.append(PATH_DIV_STR);
772 }
773 if (printDirNames) {
774 printf("comparisonDir is [%s]\n", comparisonDir.c_str());
775 }
776
777 if (!outputDir.endsWith(PATH_DIV_STR)) {
778 outputDir.append(PATH_DIV_STR);
779 }
780 if (generateDiffs) {
781 if (printDirNames) {
782 printf("writing diffs to outputDir is [%s]\n", outputDir.c_str());
783 }
784 } else {
785 if (printDirNames) {
786 printf("not writing any diffs to outputDir [%s]\n", outputDir.c_str());
787 }
788 outputDir.set("");
789 }
790
791 // If no matchSubstrings were specified, match ALL strings
792 // (except for whatever nomatchSubstrings were specified, if any).
793 if (matchSubstrings.empty()) {
794 matchSubstrings.emplace_back("");
795 }
796
797 create_diff_images(diffProc, colorThreshold, ignoreColorSpace, &differences,
798 baseDir, comparisonDir, outputDir,
799 matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, generateDiffs,
800 verbose, &summary);
801 summary.print(listFilenames, failOnResultType, failOnStatusType);
802
803 if (listFailingBase) {
804 summary.printfFailingBaseNames("\n");
805 }
806
807 if (differences.size()) {
808 qsort(differences.begin(), differences.size(), sizeof(DiffRecord), sortProc);
809 }
810
811 if (generateDiffs) {
812 print_diff_page(summary.fNumMatches, colorThreshold, differences,
813 baseDir, comparisonDir, outputDir);
814 }
815
816 int num_failing_results = 0;
817 for (int i = 0; i < DiffRecord::kResultCount; i++) {
818 if (failOnResultType[i]) {
819 num_failing_results += summary.fResultsOfType[i].size();
820 }
821 }
822 if (!failOnResultType[DiffRecord::kCouldNotCompare_Result]) {
823 for (int base = 0; base < DiffResource::kStatusCount; ++base) {
824 for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
825 if (failOnStatusType[base][comparison]) {
826 num_failing_results += summary.fStatusOfType[base][comparison].size();
827 }
828 }
829 }
830 }
831
832 // On Linux (and maybe other platforms too), any results outside of the
833 // range [0...255] are wrapped (mod 256). Do the conversion ourselves, to
834 // make sure that we only return 0 when there were no failures.
835 return (num_failing_results > 255) ? 255 : num_failing_results;
836}
GLenum type
void set(const SkString &src)
Definition: SkString.h:186
bool endsWith(const char suffixStr[]) const
Definition: SkString.h:146
T & emplace_back(Args &&... args)
Definition: SkTArray.h:248
char ** argv
Definition: library.h:9
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
SkPMColor(* DiffMetricProc)(SkPMColor, SkPMColor)
Parameterized routine to compute the color of a pixel in a difference image.
Definition: skdiff.h:255
static SkPMColor compute_diff_pmcolor(SkPMColor c0, SkPMColor c1)
Definition: skdiff.h:258
void print_diff_page(const int matchCount, const int colorThreshold, const RecordArray &differences, const SkString &baseDir, const SkString &comparisonDir, const SkString &outputDir)
const int kNoError
static void usage(char *argv0)
const int kGenericError
static void create_diff_images(DiffMetricProc dmp, const int colorThreshold, bool ignoreColorSpace, 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)
static Result getResultByName(const char *name)
Definition: skdiff.cpp:23
@ kResultCount
Definition: skdiff.h:99
static bool getMatchingStatuses(char *selector, bool statuses[kStatusCount])
Definition: skdiff.cpp:98
@ kStatusCount
Definition: skdiff.h:55
uint32_t fNumMatches
Definition: skdiff_main.cpp:71
void printfFailingBaseNames(const char separator[])
FileArray fStatusOfType[DiffResource::kStatusCount][DiffResource::kStatusCount]
Definition: skdiff_main.cpp:77
FileArray fResultsOfType[DiffRecord::kResultCount]
Definition: skdiff_main.cpp:76
void print(bool listFilenames, bool failOnResultType[DiffRecord::kResultCount], bool failOnStatusType[DiffResource::kStatusCount][DiffResource::kStatusCount])

◆ string_contains_any_of()

static bool string_contains_any_of ( const SkString string,
const StringArray substrings 
)
static

Returns true if string contains any of these substrings.

Definition at line 231 of file skdiff_main.cpp.

232 {
233 for (int i = 0; i < substrings.size(); i++) {
234 if (string.contains(substrings[i].c_str())) {
235 return true;
236 }
237 }
238 return false;
239}
constexpr bool contains(std::string_view str, std::string_view needle)
Definition: SkStringView.h:41

◆ usage()

static void usage ( char *  argv0)
static

Definition at line 552 of file skdiff_main.cpp.

552 {
553 SkDebugf("Skia baseline image diff tool\n");
554 SkDebugf("\n"
555"Usage: \n"
556" %s <baseDir> <comparisonDir> [outputDir] \n", argv0);
557 SkDebugf(
558"\nArguments:"
559"\n --failonresult <result>: After comparing all file pairs, exit with nonzero"
560"\n return code (number of file pairs yielding this"
561"\n result) if any file pairs yielded this result."
562"\n This flag may be repeated, in which case the"
563"\n return code will be the number of fail pairs"
564"\n yielding ANY of these results."
565"\n --failonstatus <baseStatus> <comparisonStatus>: exit with nonzero return"
566"\n code if any file pairs yielded this status."
567"\n --help: display this info"
568"\n --listfilenames: list all filenames for each result type in stdout"
569"\n --match <substring>: compare files whose filenames contain this substring;"
570"\n if unspecified, compare ALL files."
571"\n this flag may be repeated."
572"\n --nocolorspace: Ignore color space of images."
573"\n --nodiffs: don't write out image diffs or index.html, just generate"
574"\n report on stdout"
575"\n --nomatch <substring>: regardless of --match, DO NOT compare files whose"
576"\n filenames contain this substring."
577"\n this flag may be repeated."
578"\n --noprintdirs: do not print the directories used."
579"\n --norecurse: do not recurse into subdirectories."
580"\n --sortbymaxmismatch: sort by worst color channel mismatch;"
581"\n break ties with -sortbymismatch"
582"\n --sortbymismatch: sort by average color channel mismatch"
583"\n --threshold <n>: only report differences > n (per color channel) [default 0]"
584"\n --weighted: sort by # pixels different weighted by color difference"
585"\n"
586"\n baseDir: directory to read baseline images from."
587"\n comparisonDir: directory to read comparison images from"
588"\n outputDir: directory to write difference images and index.html to;"
589"\n defaults to comparisonDir"
590"\n"
591"\nIf no sort is specified, it will sort by fraction of pixels mismatching."
592"\n");
593}

Variable Documentation

◆ kGenericError

const int kGenericError = -1

Definition at line 596 of file skdiff_main.cpp.

◆ kNoError

const int kNoError = 0

Definition at line 595 of file skdiff_main.cpp.