180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/* 280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2011 Google Inc. 380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be 580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file. 680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 7363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "skdiff.h" 8363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "skdiff_html.h" 9363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "skdiff_utils.h" 10363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkBitmap.h" 1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkData.h" 1258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "SkForceLinking.h" 1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkImageDecoder.h" 1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkImageEncoder.h" 1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkOSFile.h" 1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkStream.h" 1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTDArray.h" 1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTemplates.h" 1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTSearch.h" 2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTypes.h" 2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 2258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger__SK_FORCE_IMAGE_DECODER_LINKING; 2358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger 2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/** 2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * skdiff 2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Given three directory names, expects to find identically-named files in 2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * each of the first two; the first are treated as a set of baseline, 2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * the second a set of variant images, and a diff image is written into the 3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * third directory for each pair. 3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Creates an index.html in the current third directory to compare each 3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * pair that does not match exactly. 3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Recursively descends directories, unless run with --norecurse. 3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * 3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Returns zero exit code if all images match across baseDir and comparisonDir. 3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */ 3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutypedef SkTDArray<SkString*> StringArray; 3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutypedef StringArray FileArray; 4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustruct DiffSummary { 4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DiffSummary () 43363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger : fNumMatches(0) 44363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger , fNumMismatches(0) 45363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger , fMaxMismatchV(0) 46363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger , fMaxMismatchPercent(0) { }; 4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ~DiffSummary() { 49363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < DiffRecord::kResultCount; ++i) { 5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fResultsOfType[i].deleteAll(); 5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 52363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int base = 0; base < DiffResource::kStatusCount; ++base) { 53363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) { 54363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fStatusOfType[base][comparison].deleteAll(); 55363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 56363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32_t fNumMatches; 6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32_t fNumMismatches; 6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32_t fMaxMismatchV; 6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru float fMaxMismatchPercent; 6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 64363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger FileArray fResultsOfType[DiffRecord::kResultCount]; 65363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger FileArray fStatusOfType[DiffResource::kStatusCount][DiffResource::kStatusCount]; 66363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 67363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger void printContents(const FileArray& fileArray, 68363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const char* baseStatus, const char* comparisonStatus, 69363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool listFilenames) { 70363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int n = fileArray.count(); 71363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printf("%d file pairs %s in baseDir and %s in comparisonDir", 72363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger n, baseStatus, comparisonStatus); 73363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (listFilenames) { 74363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printf(": "); 75363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < n; ++i) { 76363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printf("%s ", fileArray[i]->c_str()); 77363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 78363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 79363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printf("\n"); 80363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 81363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 82363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger void printStatus(bool listFilenames, 83363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool failOnStatusType[DiffResource::kStatusCount] 84363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger [DiffResource::kStatusCount]) { 85363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger typedef DiffResource::Status Status; 86363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 87363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int base = 0; base < DiffResource::kStatusCount; ++base) { 88363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger Status baseStatus = static_cast<Status>(base); 89363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) { 90363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger Status comparisonStatus = static_cast<Status>(comparison); 91363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const FileArray& fileArray = fStatusOfType[base][comparison]; 92363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (fileArray.count() > 0) { 93363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (failOnStatusType[base][comparison]) { 94363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printf(" [*] "); 95363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printf(" [_] "); 97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printContents(fileArray, 99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffResource::getStatusDescription(baseStatus), 100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffResource::getStatusDescription(comparisonStatus), 101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger listFilenames); 102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Print a line about the contents of this FileArray to stdout. 10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru void printContents(const FileArray& fileArray, const char* headerText, bool listFilenames) { 10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int n = fileArray.count(); 11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("%d file pairs %s", n, headerText); 11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (listFilenames) { 11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf(": "); 11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < n; ++i) { 11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("%s ", fileArray[i]->c_str()); 11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("\n"); 11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 120363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger void print(bool listFilenames, bool failOnResultType[DiffRecord::kResultCount], 121363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool failOnStatusType[DiffResource::kStatusCount] 122363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger [DiffResource::kStatusCount]) { 12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("\ncompared %d file pairs:\n", fNumMatches + fNumMismatches); 124363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int resultInt = 0; resultInt < DiffRecord::kResultCount; ++resultInt) { 125363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffRecord::Result result = static_cast<DiffRecord::Result>(resultInt); 12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (failOnResultType[result]) { 12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("[*] "); 12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("[_] "); 13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 131363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printContents(fResultsOfType[result], DiffRecord::getResultDescription(result), 132363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger listFilenames); 133363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (DiffRecord::kCouldNotCompare_Result == result) { 134363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger printStatus(listFilenames, failOnStatusType); 135363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("(results marked with [*] will cause nonzero return value)\n"); 13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("\nnumber of mismatching file pairs: %d\n", fNumMismatches); 13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fNumMismatches > 0) { 14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("Maximum pixel intensity mismatch %d\n", fMaxMismatchV); 14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("Largest area mismatch was %.2f%% of pixels\n",fMaxMismatchPercent); 14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru void add (DiffRecord* drp) { 14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru uint32_t mismatchValue; 14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 148363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (drp->fBase.fFilename.equals(drp->fComparison.fFilename)) { 149363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fResultsOfType[drp->fResult].push(new SkString(drp->fBase.fFilename)); 150363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 151363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkString* blame = new SkString("("); 152363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger blame->append(drp->fBase.fFilename); 153363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger blame->append(", "); 154363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger blame->append(drp->fComparison.fFilename); 155363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger blame->append(")"); 156363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fResultsOfType[drp->fResult].push(blame); 157363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru switch (drp->fResult) { 159363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kEqualBits_Result: 16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fNumMatches++; 16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 162363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kEqualPixels_Result: 16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fNumMatches++; 16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 165363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kDifferentSizes_Result: 16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fNumMismatches++; 16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 168363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kDifferentPixels_Result: 16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fNumMismatches++; 17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (drp->fFractionDifference * 100 > fMaxMismatchPercent) { 17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fMaxMismatchPercent = drp->fFractionDifference * 100; 17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru mismatchValue = MAX3(drp->fMaxMismatchR, drp->fMaxMismatchG, 17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru drp->fMaxMismatchB); 17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (mismatchValue > fMaxMismatchV) { 17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fMaxMismatchV = mismatchValue; 17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 179363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kCouldNotCompare_Result: 18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru fNumMismatches++; 181363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fStatusOfType[drp->fBase.fStatus][drp->fComparison.fStatus].push( 182363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger new SkString(drp->fBase.fFilename)); 18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 184363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger case DiffRecord::kUnknown_Result: 18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDEBUGFAIL("adding uncategorized DiffRecord"); 18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru default: 18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDEBUGFAIL("adding DiffRecord with unhandled fResult value"); 18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru break; 19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}; 19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// Returns true if string contains any of these substrings. 19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic bool string_contains_any_of(const SkString& string, 19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const StringArray& substrings) { 19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (int i = 0; i < substrings.count(); i++) { 19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (string.contains(substrings[i]->c_str())) { 19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return true; 20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return false; 20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// Internal (potentially recursive) implementation of get_file_list. 20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void get_file_list_subdir(const SkString& rootDir, const SkString& subDir, 20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const StringArray& matchSubstrings, 20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const StringArray& nomatchSubstrings, 20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool recurseIntoSubdirs, FileArray *files) { 21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool isSubDirEmpty = subDir.isEmpty(); 21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString dir(rootDir); 21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!isSubDirEmpty) { 21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dir.append(PATH_DIV_STR); 21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru dir.append(subDir); 21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Iterate over files (not directories) within dir. 21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkOSFile::Iter fileIterator(dir.c_str()); 21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString fileName; 22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (fileIterator.next(&fileName, false)) { 22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (fileName.startsWith(".")) { 22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString pathRelativeToRootDir(subDir); 22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!isSubDirEmpty) { 22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pathRelativeToRootDir.append(PATH_DIV_STR); 22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pathRelativeToRootDir.append(fileName); 22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (string_contains_any_of(pathRelativeToRootDir, matchSubstrings) && 23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru !string_contains_any_of(pathRelativeToRootDir, nomatchSubstrings)) { 23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru files->push(new SkString(pathRelativeToRootDir)); 23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Recurse into any non-ignored subdirectories. 23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (recurseIntoSubdirs) { 23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkOSFile::Iter dirIterator(dir.c_str()); 23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString dirName; 23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (dirIterator.next(&dirName, true)) { 24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (dirName.startsWith(".")) { 24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString pathRelativeToRootDir(subDir); 24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!isSubDirEmpty) { 24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pathRelativeToRootDir.append(PATH_DIV_STR); 24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru pathRelativeToRootDir.append(dirName); 24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!string_contains_any_of(pathRelativeToRootDir, nomatchSubstrings)) { 24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru get_file_list_subdir(rootDir, pathRelativeToRootDir, 25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, 25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru files); 25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// Iterate over dir and get all files whose filename: 25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// - matches any of the substrings in matchSubstrings, but... 25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// - DOES NOT match any of the substrings in nomatchSubstrings 26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// - DOES NOT start with a dot (.) 26180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// Adds the matching files to the list in *files. 26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void get_file_list(const SkString& dir, 26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const StringArray& matchSubstrings, 26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const StringArray& nomatchSubstrings, 26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool recurseIntoSubdirs, FileArray *files) { 26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru get_file_list_subdir(dir, SkString(""), 26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, 26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru files); 26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void release_file_list(FileArray *files) { 27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru files->deleteAll(); 27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// Comparison routines for qsort, sort by file names. 27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int compare_file_name_metrics(SkString **lhs, SkString **rhs) { 27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return strcmp((*lhs)->c_str(), (*rhs)->c_str()); 27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 280363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerclass AutoReleasePixels { 281363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerpublic: 282363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger AutoReleasePixels(DiffRecord* drp) 283363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger : fDrp(drp) { 284363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(drp != NULL); 285363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 286363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger ~AutoReleasePixels() { 287363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fDrp->fBase.fBitmap.setPixelRef(NULL); 288363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fDrp->fComparison.fBitmap.setPixelRef(NULL); 289363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fDrp->fDifference.fBitmap.setPixelRef(NULL); 290363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger fDrp->fWhite.fBitmap.setPixelRef(NULL); 291363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 292363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 293363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerprivate: 294363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffRecord* fDrp; 295363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}; 296363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 297363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void get_bounds(DiffResource& resource, const char* name) { 298363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (resource.fBitmap.empty() && !DiffResource::isStatusFailed(resource.fStatus)) { 299363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkAutoDataUnref fileBits(read_file(resource.fFullPath.c_str())); 300363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (NULL == fileBits) { 301363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDebugf("WARNING: couldn't read %s file <%s>\n", name, resource.fFullPath.c_str()); 302363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger resource.fStatus = DiffResource::kCouldNotRead_Status; 303363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 304363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bitmap(fileBits, resource, SkImageDecoder::kDecodeBounds_Mode); 305363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 306363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 307363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 308363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 309363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic void get_bounds(DiffRecord& drp) { 310363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bounds(drp.fBase, "base"); 311363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bounds(drp.fComparison, "comparison"); 312363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 313363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// Creates difference images, returns the number that have a 0 metric. 31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/// If outputDir.isEmpty(), don't write out diff files. 31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void create_diff_images (DiffMetricProc dmp, 31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const int colorThreshold, 31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru RecordArray* differences, 31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkString& baseDir, 32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkString& comparisonDir, 32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const SkString& outputDir, 32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const StringArray& matchSubstrings, 32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru const StringArray& nomatchSubstrings, 32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool recurseIntoSubdirs, 325363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool getBounds, 32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DiffSummary* summary) { 32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(!baseDir.isEmpty()); 32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkASSERT(!comparisonDir.isEmpty()); 32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FileArray baseFiles; 33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru FileArray comparisonFiles; 33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru get_file_list(baseDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, &baseFiles); 33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru get_file_list(comparisonDir, matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, 33580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru &comparisonFiles); 33680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!baseFiles.isEmpty()) { 33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru qsort(baseFiles.begin(), baseFiles.count(), sizeof(SkString*), 33980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkCastForQSort(compare_file_name_metrics)); 34080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 34180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!comparisonFiles.isEmpty()) { 34280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru qsort(comparisonFiles.begin(), comparisonFiles.count(), 34380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sizeof(SkString*), SkCastForQSort(compare_file_name_metrics)); 34480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int i = 0; 34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int j = 0; 34880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru while (i < baseFiles.count() && 35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru j < comparisonFiles.count()) { 35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 352363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkString basePath(baseDir); 353363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkString comparisonPath(comparisonDir); 35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 355363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffRecord *drp = new DiffRecord; 356363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int v = strcmp(baseFiles[i]->c_str(), comparisonFiles[j]->c_str()); 35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (v < 0) { 35980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // in baseDir, but not in comparisonDir 360363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fResult = DiffRecord::kCouldNotCompare_Result; 361363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 362363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger basePath.append(*baseFiles[i]); 363363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger comparisonPath.append(*baseFiles[i]); 364363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 365363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFilename = *baseFiles[i]; 366363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFullPath = basePath; 367363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fStatus = DiffResource::kExists_Status; 368363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 369363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFilename = *baseFiles[i]; 370363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFullPath = comparisonPath; 371363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fStatus = DiffResource::kDoesNotExist_Status; 372363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ++i; 37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (v > 0) { 37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // in comparisonDir, but not in baseDir 376363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fResult = DiffRecord::kCouldNotCompare_Result; 377363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 378363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger basePath.append(*comparisonFiles[j]); 379363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger comparisonPath.append(*comparisonFiles[j]); 380363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 381363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFilename = *comparisonFiles[j]; 382363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFullPath = basePath; 383363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fStatus = DiffResource::kDoesNotExist_Status; 384363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 385363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFilename = *comparisonFiles[j]; 386363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFullPath = comparisonPath; 387363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fStatus = DiffResource::kExists_Status; 388363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 38980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ++j; 39080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 39180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Found the same filename in both baseDir and comparisonDir. 392363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(DiffRecord::kUnknown_Result == drp->fResult); 393363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 394363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger basePath.append(*baseFiles[i]); 395363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger comparisonPath.append(*comparisonFiles[j]); 396363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 397363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFilename = *baseFiles[i]; 398363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFullPath = basePath; 399363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fStatus = DiffResource::kExists_Status; 400363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 401363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFilename = *comparisonFiles[j]; 402363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFullPath = comparisonPath; 403363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fStatus = DiffResource::kExists_Status; 404363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 405363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkAutoDataUnref baseFileBits(read_file(drp->fBase.fFullPath.c_str())); 406363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (NULL != baseFileBits) { 407363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fStatus = DiffResource::kRead_Status; 408363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 409363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkAutoDataUnref comparisonFileBits(read_file(drp->fComparison.fFullPath.c_str())); 410363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (NULL != comparisonFileBits) { 411363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fStatus = DiffResource::kRead_Status; 412363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 413363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (NULL == baseFileBits || NULL == comparisonFileBits) { 414363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (NULL == baseFileBits) { 415363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fStatus = DiffResource::kCouldNotRead_Status; 416363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 417363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (NULL == comparisonFileBits) { 418363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fStatus = DiffResource::kCouldNotRead_Status; 419363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 420363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fResult = DiffRecord::kCouldNotCompare_Result; 421363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 422363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else if (are_buffers_equal(baseFileBits, comparisonFileBits)) { 423363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fResult = DiffRecord::kEqualBits_Result; 424363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 42580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 426363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger AutoReleasePixels arp(drp); 427363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bitmap(baseFileBits, drp->fBase, SkImageDecoder::kDecodePixels_Mode); 428363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bitmap(comparisonFileBits, drp->fComparison, 429363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkImageDecoder::kDecodePixels_Mode); 430363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (DiffResource::kDecoded_Status == drp->fBase.fStatus && 431363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffResource::kDecoded_Status == drp->fComparison.fStatus) { 43280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru create_and_write_diff_image(drp, dmp, colorThreshold, 433363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger outputDir, drp->fBase.fFilename); 43480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 435363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fResult = DiffRecord::kCouldNotCompare_Result; 43680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 43780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 438363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 43980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ++i; 44080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru ++j; 44180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 442363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 443363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (getBounds) { 444363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bounds(*drp); 445363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 446363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkASSERT(DiffRecord::kUnknown_Result != drp->fResult); 44780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru differences->push(drp); 44880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru summary->add(drp); 44980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 45080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 45180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (; i < baseFiles.count(); ++i) { 45280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // files only in baseDir 453363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffRecord *drp = new DiffRecord(); 454363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFilename = *baseFiles[i]; 455363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFullPath = baseDir; 456363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFullPath.append(drp->fBase.fFilename); 457363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fStatus = DiffResource::kExists_Status; 458363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 459363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFilename = *baseFiles[i]; 460363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFullPath = comparisonDir; 461363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFullPath.append(drp->fComparison.fFilename); 462363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fStatus = DiffResource::kDoesNotExist_Status; 463363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 464363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fResult = DiffRecord::kCouldNotCompare_Result; 465363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (getBounds) { 466363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bounds(*drp); 467363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 46880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru differences->push(drp); 46980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru summary->add(drp); 47080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 47180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 47280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (; j < comparisonFiles.count(); ++j) { 47380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // files only in comparisonDir 474363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffRecord *drp = new DiffRecord(); 475363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFilename = *comparisonFiles[j]; 476363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFullPath = baseDir; 477363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fFullPath.append(drp->fBase.fFilename); 478363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fBase.fStatus = DiffResource::kDoesNotExist_Status; 479363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 480363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFilename = *comparisonFiles[j]; 481363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFullPath = comparisonDir; 482363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fFullPath.append(drp->fComparison.fFilename); 483363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fComparison.fStatus = DiffResource::kExists_Status; 484363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 485363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger drp->fResult = DiffRecord::kCouldNotCompare_Result; 486363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (getBounds) { 487363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger get_bounds(*drp); 488363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 48980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru differences->push(drp); 49080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru summary->add(drp); 49180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 49280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 49380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru release_file_list(&baseFiles); 49480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru release_file_list(&comparisonFiles); 49580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 49680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 49780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void usage (char * argv0) { 49880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDebugf("Skia baseline image diff tool\n"); 49980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDebugf("\n" 50080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"Usage: \n" 501363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger" %s <baseDir> <comparisonDir> [outputDir] \n", argv0); 50280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDebugf( 50380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\nArguments:" 50480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --failonresult <result>: After comparing all file pairs, exit with nonzero" 50580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n return code (number of file pairs yielding this" 50680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n result) if any file pairs yielded this result." 50780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n This flag may be repeated, in which case the" 50880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n return code will be the number of fail pairs" 50980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n yielding ANY of these results." 510363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger"\n --failonstatus <baseStatus> <comparisonStatus>: exit with nonzero return" 511363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger"\n code if any file pairs yielded this status." 51280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --help: display this info" 51380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --listfilenames: list all filenames for each result type in stdout" 51480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --match <substring>: compare files whose filenames contain this substring;" 51580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n if unspecified, compare ALL files." 51680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n this flag may be repeated." 51780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --nodiffs: don't write out image diffs or index.html, just generate" 51880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n report on stdout" 51980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --nomatch <substring>: regardless of --match, DO NOT compare files whose" 52080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n filenames contain this substring." 52180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n this flag may be repeated." 52280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --noprintdirs: do not print the directories used." 52380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --norecurse: do not recurse into subdirectories." 52480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --sortbymaxmismatch: sort by worst color channel mismatch;" 52580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n break ties with -sortbymismatch" 52680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --sortbymismatch: sort by average color channel mismatch" 52780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --threshold <n>: only report differences > n (per color channel) [default 0]" 52880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n --weighted: sort by # pixels different weighted by color difference" 52980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n" 53080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n baseDir: directory to read baseline images from." 53180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n comparisonDir: directory to read comparison images from" 53280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n outputDir: directory to write difference images and index.html to;" 53380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n defaults to comparisonDir" 53480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n" 53580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\nIf no sort is specified, it will sort by fraction of pixels mismatching." 53680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"\n"); 53780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 53880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 53980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruconst int kNoError = 0; 54080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruconst int kGenericError = -1; 54180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 54280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint tool_main(int argc, char** argv); 54380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint tool_main(int argc, char** argv) { 54480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DiffMetricProc diffProc = compute_diff_pmcolor; 54580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int (*sortProc)(const void*, const void*) = compare<CompareDiffMetrics>; 54680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 54780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // Maximum error tolerated in any one color channel in any one pixel before 54880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // a difference is reported. 54980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int colorThreshold = 0; 55080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString baseDir; 55180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString comparisonDir; 55280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkString outputDir; 55380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 55480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru StringArray matchSubstrings; 55580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru StringArray nomatchSubstrings; 55680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 55780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool generateDiffs = true; 55880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool listFilenames = false; 55980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool printDirNames = true; 56080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru bool recurseIntoSubdirs = true; 56180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 56280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru RecordArray differences; 56380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru DiffSummary summary; 56480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 565363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool failOnResultType[DiffRecord::kResultCount]; 566363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < DiffRecord::kResultCount; i++) { 56780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru failOnResultType[i] = false; 56880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 56980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 570363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool failOnStatusType[DiffResource::kStatusCount][DiffResource::kStatusCount]; 571363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int base = 0; base < DiffResource::kStatusCount; ++base) { 572363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) { 573363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger failOnStatusType[base][comparison] = false; 574363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 575363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 576363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 57780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int i; 57880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int numUnflaggedArguments = 0; 57980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (i = 1; i < argc; i++) { 58080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--failonresult")) { 581363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (argc == ++i) { 582363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDebugf("failonresult expects one argument.\n"); 583363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger continue; 584363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 585363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffRecord::Result type = DiffRecord::getResultByName(argv[i]); 586363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (type != DiffRecord::kResultCount) { 587363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger failOnResultType[type] = true; 588363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 589363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDebugf("ignoring unrecognized result <%s>\n", argv[i]); 590363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 591363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger continue; 592363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 593363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!strcmp(argv[i], "--failonstatus")) { 594363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (argc == ++i) { 595363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDebugf("failonstatus missing base status.\n"); 596363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger continue; 597363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 598363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool baseStatuses[DiffResource::kStatusCount]; 599363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!DiffResource::getMatchingStatuses(argv[i], baseStatuses)) { 600363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDebugf("unrecognized base status <%s>\n", argv[i]); 601363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 602363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 603363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (argc == ++i) { 604363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDebugf("failonstatus missing comparison status.\n"); 605363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger continue; 606363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 607363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool comparisonStatuses[DiffResource::kStatusCount]; 608363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!DiffResource::getMatchingStatuses(argv[i], comparisonStatuses)) { 609363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkDebugf("unrecognized comarison status <%s>\n", argv[i]); 610363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 611363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 612363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int base = 0; base < DiffResource::kStatusCount; ++base) { 613363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) { 614363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger failOnStatusType[base][comparison] |= 615363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger baseStatuses[base] && comparisonStatuses[comparison]; 616363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 617363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 61880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 61980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 62080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--help")) { 62180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru usage(argv[0]); 62280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return kNoError; 62380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 62480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--listfilenames")) { 62580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru listFilenames = true; 62680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 62780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 62880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--match")) { 62980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matchSubstrings.push(new SkString(argv[++i])); 63080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 63180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 63280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--nodiffs")) { 63380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru generateDiffs = false; 63480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 63580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 63680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--nomatch")) { 63780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru nomatchSubstrings.push(new SkString(argv[++i])); 63880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 63980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 64080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--noprintdirs")) { 64180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printDirNames = false; 64280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 64380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 64480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--norecurse")) { 64580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru recurseIntoSubdirs = false; 64680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 64780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 64880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--sortbymaxmismatch")) { 64980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sortProc = compare<CompareDiffMaxMismatches>; 65080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 65180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 65280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--sortbymismatch")) { 65380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sortProc = compare<CompareDiffMeanMismatches>; 65480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 65580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 65680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--threshold")) { 65780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru colorThreshold = atoi(argv[++i]); 65880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 65980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 66080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!strcmp(argv[i], "--weighted")) { 66180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sortProc = compare<CompareDiffWeighted>; 66280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 66380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 66480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (argv[i][0] != '-') { 66580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru switch (numUnflaggedArguments++) { 66680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case 0: 66780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru baseDir.set(argv[i]); 66880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 66980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case 1: 67080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru comparisonDir.set(argv[i]); 67180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 67280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru case 2: 67380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru outputDir.set(argv[i]); 67480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru continue; 67580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru default: 67680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDebugf("extra unflagged argument <%s>\n", argv[i]); 67780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru usage(argv[0]); 67880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return kGenericError; 67980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 68080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 68180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 68280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru SkDebugf("Unrecognized argument <%s>\n", argv[i]); 68380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru usage(argv[0]); 68480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return kGenericError; 68580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 68680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 68780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (numUnflaggedArguments == 2) { 68880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru outputDir = comparisonDir; 68980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else if (numUnflaggedArguments != 3) { 69080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru usage(argv[0]); 69180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return kGenericError; 69280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 69380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 69480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!baseDir.endsWith(PATH_DIV_STR)) { 69580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru baseDir.append(PATH_DIV_STR); 69680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 69780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (printDirNames) { 69880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("baseDir is [%s]\n", baseDir.c_str()); 69980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 70080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 70180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!comparisonDir.endsWith(PATH_DIV_STR)) { 70280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru comparisonDir.append(PATH_DIV_STR); 70380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 70480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (printDirNames) { 70580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("comparisonDir is [%s]\n", comparisonDir.c_str()); 70680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 70780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 70880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (!outputDir.endsWith(PATH_DIV_STR)) { 70980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru outputDir.append(PATH_DIV_STR); 71080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 71180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (generateDiffs) { 71280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (printDirNames) { 71380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("writing diffs to outputDir is [%s]\n", outputDir.c_str()); 71480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 71580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } else { 71680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (printDirNames) { 71780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru printf("not writing any diffs to outputDir [%s]\n", outputDir.c_str()); 71880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 71980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru outputDir.set(""); 72080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 72180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 72280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // If no matchSubstrings were specified, match ALL strings 72380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // (except for whatever nomatchSubstrings were specified, if any). 72480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (matchSubstrings.isEmpty()) { 72580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matchSubstrings.push(new SkString("")); 72680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 72780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 72880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru create_diff_images(diffProc, colorThreshold, &differences, 72980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru baseDir, comparisonDir, outputDir, 730363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, generateDiffs, 731363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger &summary); 732363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger summary.print(listFilenames, failOnResultType, failOnStatusType); 73380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 73480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (differences.count()) { 73580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru qsort(differences.begin(), differences.count(), 73680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru sizeof(DiffRecord*), sortProc); 73780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 73880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 73980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (generateDiffs) { 74080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru print_diff_page(summary.fNumMatches, colorThreshold, differences, 74180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru baseDir, comparisonDir, outputDir); 74280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 74380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 74480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru for (i = 0; i < differences.count(); i++) { 74580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru delete differences[i]; 74680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 74780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru matchSubstrings.deleteAll(); 74880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru nomatchSubstrings.deleteAll(); 74980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 75080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru int num_failing_results = 0; 751363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int i = 0; i < DiffRecord::kResultCount; i++) { 75280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru if (failOnResultType[i]) { 75380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru num_failing_results += summary.fResultsOfType[i].count(); 75480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 75580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru } 756363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!failOnResultType[DiffRecord::kCouldNotCompare_Result]) { 757363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int base = 0; base < DiffResource::kStatusCount; ++base) { 758363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) { 759363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (failOnStatusType[base][comparison]) { 760363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger num_failing_results += summary.fStatusOfType[base][comparison].count(); 761363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 762363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 763363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 764363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 76580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 76680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // On Linux (and maybe other platforms too), any results outside of the 76780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // range [0...255] are wrapped (mod 256). Do the conversion ourselves, to 76880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru // make sure that we only return 0 when there were no failures. 76980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return (num_failing_results > 255) ? 255 : num_failing_results; 77080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 77180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru 77280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if !defined SK_BUILD_FOR_IOS 77380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint main(int argc, char * const argv[]) { 77480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru return tool_main(argc, (char**) argv); 77580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru} 77680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif 777