summaryrefslogtreecommitdiffstats
path: root/Tools/WebKitTestRunner/cg/TestInvocationCG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/WebKitTestRunner/cg/TestInvocationCG.cpp')
-rw-r--r--Tools/WebKitTestRunner/cg/TestInvocationCG.cpp154
1 files changed, 154 insertions, 0 deletions
diff --git a/Tools/WebKitTestRunner/cg/TestInvocationCG.cpp b/Tools/WebKitTestRunner/cg/TestInvocationCG.cpp
new file mode 100644
index 0000000..cba2908
--- /dev/null
+++ b/Tools/WebKitTestRunner/cg/TestInvocationCG.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "TestInvocation.h"
+
+#include "PlatformWebView.h"
+#include "TestController.h"
+#include <ImageIO/CGImageDestination.h>
+#include <WebKit2/WKImageCG.h>
+#include <wtf/MD5.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/StringExtras.h>
+
+#if PLATFORM(MAC)
+#include <LaunchServices/UTCoreTypes.h>
+#endif
+
+#if PLATFORM(WIN)
+static const CFStringRef kUTTypePNG = CFSTR("public.png");
+#endif
+
+namespace WTR {
+
+static CGContextRef createCGContextFromImage(WKImageRef wkImage)
+{
+ RetainPtr<CGImageRef> image(AdoptCF, WKImageCreateCGImage(wkImage));
+
+ size_t pixelsWide = CGImageGetWidth(image.get());
+ size_t pixelsHigh = CGImageGetHeight(image.get());
+ size_t rowBytes = (4 * pixelsWide + 63) & ~63;
+ void* buffer = calloc(pixelsHigh, rowBytes);
+
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = CGBitmapContextCreate(buffer, pixelsWide, pixelsHigh, 8, rowBytes, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
+ CGColorSpaceRelease(colorSpace);
+
+ CGContextDrawImage(context, CGRectMake(0, 0, pixelsWide, pixelsHigh), image.get());
+
+ return context;
+}
+
+void computeMD5HashStringForContext(CGContextRef bitmapContext, char hashString[33])
+{
+ ASSERT(CGBitmapContextGetBitsPerPixel(bitmapContext) == 32); // ImageDiff assumes 32 bit RGBA, we must as well.
+ size_t pixelsHigh = CGBitmapContextGetHeight(bitmapContext);
+ size_t pixelsWide = CGBitmapContextGetWidth(bitmapContext);
+ size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmapContext);
+
+ // We need to swap the bytes to ensure consistent hashes independently of endianness
+ MD5 md5;
+ unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmapContext));
+#if PLATFORM(MAC)
+ if ((CGBitmapContextGetBitmapInfo(bitmapContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Big) {
+ for (unsigned row = 0; row < pixelsHigh; row++) {
+ Vector<uint8_t> buffer(4 * pixelsWide);
+ for (unsigned column = 0; column < pixelsWide; column++)
+ buffer[column] = OSReadLittleInt32(bitmapData, 4 * column);
+ md5.addBytes(buffer);
+ bitmapData += bytesPerRow;
+ }
+ } else {
+#endif
+ for (unsigned row = 0; row < pixelsHigh; row++) {
+ md5.addBytes(bitmapData, 4 * pixelsWide);
+ bitmapData += bytesPerRow;
+ }
+#if PLATFORM(MAC)
+ }
+#endif
+
+ Vector<uint8_t, 16> hash;
+ md5.checksum(hash);
+
+ hashString[0] = '\0';
+ for (int i = 0; i < 16; i++)
+ snprintf(hashString, 33, "%s%02x", hashString, hash[i]);
+}
+
+static void dumpBitmap(CGContextRef bitmapContext)
+{
+ RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(bitmapContext));
+ RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0));
+ RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0));
+ CGImageDestinationAddImage(imageDest.get(), image.get(), 0);
+ CGImageDestinationFinalize(imageDest.get());
+
+ const unsigned char* data = CFDataGetBytePtr(imageData.get());
+ const size_t dataLength = CFDataGetLength(imageData.get());
+
+
+ fprintf(stdout, "Content-Type: %s\n", "image/png");
+ fprintf(stdout, "Content-Length: %lu\n", static_cast<unsigned long>(dataLength));
+
+ const size_t bytesToWriteInOneChunk = 1 << 15;
+ size_t dataRemainingToWrite = dataLength;
+ while (dataRemainingToWrite) {
+ size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk);
+ size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout);
+ if (bytesWritten != bytesToWriteInThisChunk)
+ break;
+ dataRemainingToWrite -= bytesWritten;
+ data += bytesWritten;
+ }
+}
+
+void TestInvocation::dumpPixelsAndCompareWithExpected(WKImageRef image)
+{
+ CGContextRef context = createCGContextFromImage(image);
+
+ // Compute the hash of the bitmap context pixels
+ char actualHash[33];
+ computeMD5HashStringForContext(context, actualHash);
+ fprintf(stdout, "\nActualHash: %s\n", actualHash);
+
+ // Check the computed hash against the expected one and dump image on mismatch
+ bool hashesMatch = false;
+ if (m_expectedPixelHash.length() > 0) {
+ ASSERT(m_expectedPixelHash.length() == 32);
+
+ fprintf(stdout, "\nExpectedHash: %s\n", m_expectedPixelHash.c_str());
+
+ // FIXME: Do case insensitive compare.
+ if (m_expectedPixelHash == actualHash)
+ hashesMatch = true;
+ }
+
+ if (!hashesMatch)
+ dumpBitmap(context);
+}
+
+} // namespace WTR