WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-61942-20110617170929.patch (text/plain), 13.39 KB, created by
Leandro Pereira
on 2011-06-17 13:09:31 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Leandro Pereira
Created:
2011-06-17 13:09:31 PDT
Size:
13.39 KB
patch
obsolete
>Index: Tools/ChangeLog >=================================================================== >--- Tools/ChangeLog (revision 89163) >+++ Tools/ChangeLog (working copy) >@@ -1,3 +1,30 @@ >+2011-06-17 Leandro Pereira <leandro@profusion.mobi> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ [EFL] Add Evas-based ImageDiff implementation. >+ https://bugs.webkit.org/show_bug.cgi?id=61942 >+ >+ Build system changes will be performed as soon as the complete >+ DumpRenderTree implementation is upstreamed. >+ >+ * DumpRenderTree/efl/ImageDiff.cpp: Added. >+ (pixelFromImageData): >+ (differenceImageFromDifferenceBuffer): >+ (computeDistanceBetweenPixelComponents): >+ (calculatePixelDifference): >+ (calculateDifference): >+ (getTemporaryFile): >+ (printImage): >+ (printImageDifferences): >+ (resizeEcoreEvasIfNeeded): >+ (readImageFromStdin): >+ (parseCommandLineOptions): >+ (shutdownEfl): >+ (abortWithErrorMessage): >+ (initEfl): >+ (main): >+ > 2011-05-25 Brent Fulgham <bfulgham@webkit.org> > > Reviewed by Brian Weinstein. >Index: Tools/DumpRenderTree/efl/ImageDiff.cpp >=================================================================== >--- Tools/DumpRenderTree/efl/ImageDiff.cpp (revision 0) >+++ Tools/DumpRenderTree/efl/ImageDiff.cpp (revision 0) >@@ -0,0 +1,348 @@ >+/* >+ * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> >+ * Copyright (C) 2010 Igalia S.L. >+ * Copyright (C) 2011 ProFUSION Embedded Systems >+ * Copyright (C) 2011 Samsung Electronics >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of >+ * its contributors may be used to endorse or promote products derived >+ * from this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED >+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY >+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; >+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND >+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+ >+#include <Ecore.h> >+#include <Ecore_Evas.h> >+#include <Evas.h> >+#include <algorithm> >+#include <cmath> >+#include <cstdio> >+#include <cstdlib> >+#include <getopt.h> >+#include <sys/stat.h> >+#include <sys/types.h> >+#include <unistd.h> >+#include <wtf/OwnArrayPtr.h> >+#include <wtf/OwnPtr.h> >+#include <wtf/PassOwnPtr.h> >+ >+enum PixelComponent { >+ Red, >+ Green, >+ Blue, >+ Alpha >+}; >+ >+static OwnPtr<Ecore_Evas> gEcoreEvas; >+static double gTolerance = 0; >+ >+static void abortWithErrorMessage(const char* errorMessage); >+ >+static unsigned char* pixelFromImageData(unsigned char* imageData, int rowStride, int x, int y) >+{ >+ return imageData + (y * rowStride) + (x << 2); >+} >+ >+static Evas_Object* differenceImageFromDifferenceBuffer(Evas* evas, unsigned char* buffer, int width, int height) >+{ >+ Evas_Object* image = evas_object_image_filled_add(evas); >+ if (!image) >+ abortWithErrorMessage("could not create difference image"); >+ >+ evas_object_image_size_set(image, width, height); >+ evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); >+ >+ unsigned char* diffPixels = static_cast<unsigned char*>(evas_object_image_data_get(image, EINA_TRUE)); >+ const int rowStride = evas_object_image_stride_get(image); >+ for (int x = 0; x < width; x++) { >+ for (int y = 0; y < height; y++) { >+ unsigned char* diffPixel = pixelFromImageData(diffPixels, rowStride, x, y); >+ diffPixel[Red] = diffPixel[Green] = diffPixel[Blue] = *buffer++; >+ diffPixel[Alpha] = 0xff; >+ } >+ } >+ >+ return image; >+} >+ >+static float computeDistanceBetweenPixelComponents(unsigned char actualComponent, unsigned char baseComponent) >+{ >+ return (actualComponent - baseComponent) / std::max<float>(255 - baseComponent, baseComponent); >+} >+ >+static float computeDistanceBetweenPixelComponents(unsigned char* actualPixel, unsigned char* basePixel, PixelComponent component) >+{ >+ return computeDistanceBetweenPixelComponents(actualPixel[component], basePixel[component]); >+} >+ >+static float calculatePixelDifference(unsigned char* basePixel, unsigned char* actualPixel) >+{ >+ const float red = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Red); >+ const float green = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Green); >+ const float blue = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Blue); >+ const float alpha = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Alpha); >+ return sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; >+} >+ >+static float calculateDifference(const Evas_Object* baselineImage, const Evas_Object* actualImage, OwnPtr<Evas_Object>& differenceImage) >+{ >+ int width, height, baselineWidth, baselineHeight; >+ evas_object_image_size_get(actualImage, &width, &height); >+ evas_object_image_size_get(baselineImage, &baselineWidth, &baselineHeight); >+ >+ if (width != baselineWidth || height != baselineHeight) { >+ printf("Error, test and reference image have different sizes.\n"); >+ return 100; // Completely different. >+ } >+ >+ OwnArrayPtr<unsigned char> diffBuffer = adoptArrayPtr(new unsigned char[width * height]); >+ if (!diffBuffer) >+ abortWithErrorMessage("could not create difference buffer"); >+ >+ const int actualRowStride = evas_object_image_stride_get(actualImage); >+ const int baseRowStride = evas_object_image_stride_get(baselineImage); >+ unsigned numberOfDifferentPixels = 0; >+ float totalDistance = 0; >+ float maxDistance = 0; >+ unsigned char* actualPixels = static_cast<unsigned char*>(evas_object_image_data_get(actualImage, EINA_FALSE)); >+ unsigned char* basePixels = static_cast<unsigned char*>(evas_object_image_data_get(baselineImage, EINA_FALSE)); >+ unsigned char* currentDiffPixel = diffBuffer.get(); >+ >+ for (int x = 0; x < width; x++) { >+ for (int y = 0; y < height; y++) { >+ unsigned char* actualPixel = pixelFromImageData(actualPixels, actualRowStride, x, y); >+ unsigned char* basePixel = pixelFromImageData(basePixels, baseRowStride, x, y); >+ >+ const float distance = calculatePixelDifference(basePixel, actualPixel); >+ *currentDiffPixel++ = static_cast<unsigned char>(distance * 255.0f); >+ >+ if (distance >= 1.0f / 255.0f) { >+ ++numberOfDifferentPixels; >+ totalDistance += distance; >+ maxDistance = std::max<float>(maxDistance, distance); >+ } >+ } >+ } >+ >+ // 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 >+ float difference = 0; >+ if (numberOfDifferentPixels) >+ difference = 100.0f * totalDistance / (height * width); >+ if (difference <= gTolerance) >+ difference = 0; >+ else { >+ difference = roundf(difference * 100.0f) / 100.0f; >+ difference = std::max(difference, 0.01f); // round to 2 decimal places >+ >+ differenceImage = adoptPtr(differenceImageFromDifferenceBuffer(evas_object_evas_get(baselineImage), diffBuffer.get(), width, height)); >+ } >+ >+ return difference; >+} >+ >+static int getTemporaryFile(char *fileName, size_t fileNameLength) >+{ >+ char* tempDirectory = getenv("TMPDIR"); >+ if (!tempDirectory) >+ tempDirectory = getenv("TEMP"); >+ >+ if (tempDirectory) >+ snprintf(fileName, fileNameLength, "%s/ImageDiffXXXXXX.png", tempDirectory); >+ else { >+#if __linux__ >+ strcpy(fileName, "/dev/shm/ImageDiffXXXXXX.png"); >+ const int fileDescriptor = mkstemps(fileName, sizeof(".png") - 1); >+ if (fileDescriptor >= 0) >+ return fileDescriptor; >+#endif // __linux__ >+ >+ strcpy(fileName, "ImageDiffXXXXXX.png"); >+ } >+ >+ return mkstemps(fileName, sizeof(".png") - 1); >+} >+ >+static void printImage(Evas_Object* image) >+{ >+ char fileName[PATH_MAX]; >+ >+ const int tempImageFd = getTemporaryFile(fileName, PATH_MAX); >+ if (tempImageFd == -1) >+ abortWithErrorMessage("could not create temporary file"); >+ >+ if (evas_object_image_save(image, fileName, 0, 0)) { >+ struct stat fileInfo; >+ if (!stat(fileName, &fileInfo)) { >+ printf("Content-Length: %ld\n", fileInfo.st_size); >+ fflush(stdout); >+ >+ unsigned char buffer[2048]; >+ ssize_t bytesRead; >+ while ((bytesRead = read(tempImageFd, buffer, sizeof(buffer))) > 0) >+ write(1, buffer, bytesRead); >+ } >+ } >+ close(tempImageFd); >+ unlink(fileName); >+} >+ >+static void printImageDifferences(const Evas_Object* baselineImage, Evas_Object* actualImage) >+{ >+ OwnPtr<Evas_Object> differenceImage; >+ const float difference = calculateDifference(baselineImage, actualImage, differenceImage); >+ >+ if (difference > 0.0f) { >+ if (differenceImage) >+ printImage(differenceImage.get()); >+ >+ printf("diff: %01.2f%% failed\n", difference); >+ } else >+ printf("diff: %01.2f%% passed\n", difference); >+} >+ >+static void resizeEcoreEvasIfNeeded(Evas_Object* image) >+{ >+ int newWidth, newHeight; >+ evas_object_image_size_get(image, &newWidth, &newHeight); >+ >+ int currentWidth, currentHeight; >+ ecore_evas_screen_geometry_get(gEcoreEvas.get(), 0, 0, ¤tWidth, ¤tHeight); >+ >+ if (newWidth > currentWidth) >+ currentWidth = newWidth; >+ if (newHeight > currentHeight) >+ currentHeight = newHeight; >+ >+ ecore_evas_resize(gEcoreEvas.get(), currentWidth, currentHeight); >+} >+ >+static PassOwnPtr<Evas_Object> readImageFromStdin(Evas* evas, long imageSize) >+{ >+ OwnArrayPtr<unsigned char> imageBuffer = adoptArrayPtr(new unsigned char[imageSize]); >+ if (!imageBuffer) >+ abortWithErrorMessage("cannot allocate image"); >+ >+ const size_t bytesRead = fread(imageBuffer.get(), 1, imageSize, stdin); >+ if (!bytesRead) >+ return PassOwnPtr<Evas_Object>(); >+ >+ Evas_Object* image = evas_object_image_filled_add(evas); >+ evas_object_image_memfile_set(image, imageBuffer.get(), bytesRead, 0, 0); >+ evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); >+ >+ resizeEcoreEvasIfNeeded(image); >+ >+ return adoptPtr(image); >+} >+ >+static bool parseCommandLineOptions(int argc, char** argv) >+{ >+ static const option options[] = { >+ { "tolerance", required_argument, 0, 't' }, >+ { 0, 0, 0, 0 } >+ }; >+ int option; >+ >+ while ((option = getopt_long(argc, (char* const*)argv, "t:", options, 0)) != -1) { >+ switch (option) { >+ case 't': >+ gTolerance = atof(optarg); >+ break; >+ case '?': >+ case ':': >+ return false; >+ } >+ } >+ >+ return true; >+} >+ >+static void shutdownEfl() >+{ >+ ecore_evas_shutdown(); >+ ecore_shutdown(); >+ evas_shutdown(); >+} >+ >+static void abortWithErrorMessage(const char* errorMessage) >+{ >+ shutdownEfl(); >+ >+ printf("Error, %s.\n", errorMessage); >+ exit(EXIT_FAILURE); >+} >+ >+static Evas* initEfl() >+{ >+ evas_init(); >+ ecore_init(); >+ ecore_evas_init(); >+ >+ gEcoreEvas = adoptPtr(ecore_evas_buffer_new(1, 1)); >+ Evas* evas = ecore_evas_get(gEcoreEvas.get()); >+ if (!evas) >+ abortWithErrorMessage("could not create Ecore_Evas buffer"); >+ >+ return evas; >+} >+ >+int main(int argc, char* argv[]) >+{ >+ if (!parseCommandLineOptions(argc, argv)) >+ return EXIT_FAILURE; >+ >+ Evas* evas = initEfl(); >+ >+ OwnPtr<Evas_Object> actualImage; >+ OwnPtr<Evas_Object> baselineImage; >+ >+ char buffer[2048]; >+ while (fgets(buffer, sizeof(buffer), stdin)) { >+ char* contentLengthStart = strstr(buffer, "Content-Length: "); >+ if (!contentLengthStart) >+ continue; >+ long imageSize; >+ if (sscanf(contentLengthStart, "Content-Length: %ld", &imageSize) == 1) { >+ if (imageSize <= 0) >+ abortWithErrorMessage("image size must be specified"); >+ >+ if (!actualImage) >+ actualImage = readImageFromStdin(evas, imageSize); >+ else if (!baselineImage) >+ baselineImage = readImageFromStdin(evas, imageSize); >+ else { >+ printImageDifferences(baselineImage.get(), actualImage.get()); >+ >+ actualImage.clear(); >+ baselineImage.clear(); >+ } >+ } >+ >+ fflush(stdout); >+ } >+ >+ shutdownEfl(); >+ return EXIT_SUCCESS; >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 61942
:
95777
|
95779
|
97460
| 97642