1221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom/* 2221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. 3221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>. All rights reserved. 4221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * Copyright (C) 2011 Brent Fulgham. All rights reserved. 5221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * 6221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * Redistribution and use in source and binary forms, with or without 7221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * modification, are permitted provided that the following conditions 8221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * are met: 9221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * 1. Redistributions of source code must retain the above copyright 10221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * notice, this list of conditions and the following disclaimer. 11221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * 2. Redistributions in binary form must reproduce the above copyright 12221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * notice, this list of conditions and the following disclaimer in the 13221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * documentation and/or other materials provided with the distribution. 14221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * 15221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 16221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 19221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom */ 27392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom 28221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom// FIXME: We need to be able to include these defines from a config.h somewhere. 29221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#define JS_EXPORT_PRIVATE 30221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#define WTF_EXPORT_PRIVATE 31221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 32221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <cairo.h> 33221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <stdio.h> 34392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom#include <wtf/Platform.h> 35221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <wtf/RefPtr.h> 36221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <wtf/RetainPtr.h> 37221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 38221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#if PLATFORM(WIN) 39221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <fcntl.h> 40221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <io.h> 41221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <windows.h> 42221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#include <wtf/MathExtras.h> 43221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#endif 44221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 45221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromusing namespace std; 46221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 47221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic const int s_bufferSize = 2048; 48392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstromstatic const int s_bytesPerPixel = 4; 49392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstromstatic cairo_user_data_key_t s_imageDataKey; 50221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 51221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 52221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#if PLATFORM(WIN) 53221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#undef min 54221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#undef max 55221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 56221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic inline float strtof(const char* inputString, char** endptr) 57221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 58221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return strtod(inputString, endptr); 59221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 60221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#endif 61221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 62221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic cairo_status_t readFromData(void* closure, unsigned char* data, unsigned int length) 63221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 64221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom CFMutableDataRef dataSource = reinterpret_cast<CFMutableDataRef>(closure); 65221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 66221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom CFRange range = CFRangeMake(0, length); 67221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom CFDataGetBytes(dataSource, range, data); 68221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom CFDataDeleteBytes(dataSource, range); 69221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 70221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return CAIRO_STATUS_SUCCESS; 71221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 72221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 73221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic cairo_surface_t* createImageFromStdin(int bytesRemaining) 74221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 75221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom unsigned char buffer[s_bufferSize]; 76221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, bytesRemaining)); 77221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 78221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom while (bytesRemaining > 0) { 79221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom size_t bytesToRead = min(bytesRemaining, s_bufferSize); 80221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); 81221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom CFDataAppendBytes(data.get(), buffer, static_cast<CFIndex>(bytesRead)); 82221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom bytesRemaining -= static_cast<int>(bytesRead); 83221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 84221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 85221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return cairo_image_surface_create_from_png_stream (static_cast<cairo_read_func_t>(readFromData), data.get()); 86221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 87221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 88221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic void releaseMallocBuffer(void* data) 89221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 90221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom free(data); 91221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 92221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 93221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic inline float pixelDifference(float expected, float actual) 94221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 95221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return (actual - expected) / max<float>(255 - expected, expected); 96221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 97221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 98221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic inline void normalizeBuffer(float maxDistance, unsigned char* buffer, size_t length) 99221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 100221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (maxDistance >= 1) 101221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return; 102221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 103221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom for (size_t p = 0; p < length; ++p) 104221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom buffer[p] /= maxDistance; 105221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 106221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 107221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic cairo_surface_t* createDifferenceImage(cairo_surface_t* baselineImage, cairo_surface_t* actualImage, float& difference) 108221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 109221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom size_t width = cairo_image_surface_get_width(baselineImage); 110221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom size_t height = cairo_image_surface_get_height(baselineImage); 111221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 112221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom unsigned char* baselinePixel = cairo_image_surface_get_data(baselineImage); 113221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom unsigned char* actualPixel = cairo_image_surface_get_data(actualImage); 114221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 115221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom // Compare the content of the 2 bitmaps 116221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom void* diffBuffer = malloc(width * height); 117221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom unsigned char* diffPixel = reinterpret_cast<unsigned char*>(diffBuffer); 118221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 119221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float count = 0; 120221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float sum = 0; 121221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float maxDistance = 0; 122221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom for (size_t y = 0; y < height; ++y) { 123221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom for (size_t x = 0; x < width; ++x) { 124221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float red = pixelDifference(baselinePixel[0], actualPixel[0]); 125221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float green = pixelDifference(baselinePixel[1], actualPixel[1]); 126221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float blue = pixelDifference(baselinePixel[2], actualPixel[2]); 127221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float alpha = pixelDifference(baselinePixel[3], actualPixel[3]); 128221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 129221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0; 130221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 131221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom *diffPixel++ = static_cast<unsigned char>(distance * 255); 132221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 133221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (distance >= 1.0 / 255.0) { 134221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom ++count; 135221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom sum += distance; 136221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (distance > maxDistance) 137221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom maxDistance = distance; 138221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 139221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 140221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom baselinePixel += s_bytesPerPixel; 141221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom actualPixel += s_bytesPerPixel; 142221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 143221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 144221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 145221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image 146221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (count > 0) 147221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom difference = 100.0f * sum / (height * width); 148221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom else 149221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom difference = 0; 150221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 151221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (!difference) { 152221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom free(diffBuffer); 153221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return 0; 154221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 155221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 156221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom // Generate a normalized diff image 157221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom normalizeBuffer(maxDistance, reinterpret_cast<unsigned char*>(diffBuffer), height * width); 158221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 159221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom cairo_surface_t* diffImage = cairo_image_surface_create_for_data(diffPixel, CAIRO_FORMAT_ARGB32, width, height, width * s_bytesPerPixel); 160221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom cairo_surface_set_user_data(diffImage, &s_imageDataKey, diffBuffer, releaseMallocBuffer); 161221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 162221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return diffImage; 163221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 164221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 165221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic inline bool imageHasAlpha(cairo_surface_t* image) 166221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 167221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return (cairo_image_surface_get_format(image) == CAIRO_FORMAT_ARGB32); 168392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom} 169221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 170221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromstatic cairo_status_t writeToData(void* closure, unsigned char* data, unsigned int length) 171221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 172221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom CFMutableDataRef dataTarget = reinterpret_cast<CFMutableDataRef>(closure); 173221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 174221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom CFDataAppendBytes(dataTarget, data, length); 175221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 176221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom return CAIRO_STATUS_SUCCESS; 177221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom} 178221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 179221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstromint main(int argc, const char* argv[]) 180221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom{ 181221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#if PLATFORM(WIN) 182221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom _setmode(0, _O_BINARY); 183221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom _setmode(1, _O_BINARY); 184221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom#endif 185221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 186221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float tolerance = 0; 187392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom 188221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom for (int i = 1; i < argc; ++i) { 189221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) { 190221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (i >= argc - 1) 191221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom exit(1); 192221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom tolerance = strtof(argv[i + 1], 0); 193221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom ++i; 194221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom continue; 195221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 196221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 197221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 198392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom char buffer[s_bufferSize]; 199221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom cairo_surface_t* actualImage = 0; 200392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom cairo_surface_t* baselineImage = 0; 201392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom 202392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom while (fgets(buffer, sizeof(buffer), stdin)) { 203392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom char* newLineCharacter = strchr(buffer, '\n'); 204392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom if (newLineCharacter) 205392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom *newLineCharacter = '\0'; 206221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 207221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (!strncmp("Content-Length: ", buffer, 16)) { 208221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom strtok(buffer, " "); 209221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom int imageSize = strtol(strtok(0, " "), 0, 10); 210221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 211221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (imageSize > 0 && !actualImage) 212221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom actualImage = createImageFromStdin(imageSize); 213221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom else if (imageSize > 0 && !baselineImage) 214221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom baselineImage = createImageFromStdin(imageSize); 215221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom else 216221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom fputs("error, image size must be specified.\n", stdout); 217221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 218221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 219221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (actualImage && baselineImage) { 220392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom cairo_surface_t* diffImage = 0; 221221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom float difference = 100.0; 222221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 223221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if ((cairo_image_surface_get_width(actualImage) == cairo_image_surface_get_width(baselineImage)) 224221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom && (cairo_image_surface_get_height(actualImage) == cairo_image_surface_get_height(baselineImage)) 225221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom && (imageHasAlpha(actualImage) == imageHasAlpha(baselineImage))) { 226221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom diffImage = createDifferenceImage(actualImage, baselineImage, difference); // difference is passed by reference 227221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (difference <= tolerance) 228221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom difference = 0; 229221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom else { 230221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom difference = roundf(difference * 100.0) / 100.0; 231221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom difference = max<float>(difference, 0.01); // round to 2 decimal places 232221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } 233221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom } else 234392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom fputs("error, test and reference image have different properties.\n", stderr); 235221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom 236392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom if (difference > 0.0) { 237221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom if (diffImage) { 238221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); 239392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom cairo_surface_write_to_png_stream(diffImage, (cairo_write_func_t)writeToData, imageData.get()); 240221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom printf("Content-Length: %lu\n", CFDataGetLength(imageData.get())); 241221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); 242392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom cairo_surface_destroy(diffImage); 243392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom diffImage = 0; 244392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom } 245392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom 246392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom fprintf(stdout, "diff: %01.2f%% failed\n", difference); 247392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom } else 248392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom fprintf(stdout, "diff: %01.2f%% passed\n", difference); 249392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom 250392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom cairo_surface_destroy(actualImage); 251392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom cairo_surface_destroy(baselineImage); 252392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom actualImage = 0; 253392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom baselineImage = 0; 254392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom } 255392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom 256392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom fflush(stdout); 257392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom } 258392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom 259392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom return 0; 260392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom} 261392aa7cc7d2b122614c5393c3e357da07fd07af3Brian Carlstrom