WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Updated patch
PATCH_FILE.txt (text/plain), 78.82 KB, created by
Pierre-Olivier Latour
on 2008-10-23 19:33:18 PDT
(
hide
)
Description:
Updated patch
Filename:
MIME Type:
Creator:
Pierre-Olivier Latour
Created:
2008-10-23 19:33:18 PDT
Size:
78.82 KB
patch
obsolete
>diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog >index 9e567ec..59ad3c7 100644 >--- a/WebKitTools/ChangeLog >+++ b/WebKitTools/ChangeLog >@@ -1,3 +1,88 @@ >+2008-10-23 Pierre-Olivier Latour <pol@apple.com> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Primary changes in DumpRenderTree: >+ - Ensure font smoothing is disabled (this is also called LCD anti-aliasing and >+ is different from regular font CG anti-aliasing) as font-smoothing settings >+ depends on the display and can also be changed by the user >+ - Use a new cleared buffer for each test instead of the reusing same one to >+ avoid potential result corruption across tests >+ - Can now receive the expected pixel hash as a suffix to the test path or >+ url as "path'hash" >+ - Make sure hash is computed in a endian-independent way >+ - Improve the code that sets/restores the screen color profile >+ - Make the code more cross-platformy with std::string goodness >+ - Added an "on-screen" mode where the snapshot will take into account surfaces >+ on the window (like OpenGL content): this uses the new CG APIs on 10.5 or >+ reading from the display framebuffer on 10.4. This mode is not active by >+ default for performance reason, but must be explicitly activated from the test >+ file using the new "testOnscreen()" JS API. >+ >+ Primary changes in ImageDiff: >+ - Provide a new comparison algorithm that is more tolerant to "acceptable" >+ failures (i.e. very small differences in font rendering, which --threshold is >+ not really good at handling) >+ - Generate normalized intensity-only diff images >+ >+ Primary changes in run-webkit-tests: >+ - Take advantage of hashes for pixel tests which makes them much faster by >+ minimizing image comparisons >+ - Removed repaint options as these should be set from within test files using >+ JS API >+ - Replaced "threshold" option in by "tolerance" expressed in percents >+ - Added more logging when in "verbose" mode >+ >+ https://bugs.webkit.org/show_bug.cgi?id=21322 >+ >+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: >+ * DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h: Added. >+ * DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h: Added. >+ * DumpRenderTree/LayoutTestController.cpp: >+ (LayoutTestController::LayoutTestController): >+ (testOnscreenCallback): >+ (LayoutTestController::staticFunctions): >+ * DumpRenderTree/LayoutTestController.h: >+ (LayoutTestController::testOnscreen): >+ (LayoutTestController::setTestOnscreen): >+ (LayoutTestController::testPathOrURL): >+ (LayoutTestController::expectedPixelHash): >+ * DumpRenderTree/PixelDumpSupport.h: >+ * DumpRenderTree/cg/ImageDiffCG.cpp: >+ (strtof): >+ (releaseMallocBuffer): >+ (createDifferenceImage): >+ (imageHasAlpha): >+ (main): >+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp: >+ (computeMD5HashStringForBitmapContext): >+ (dumpWebViewAsPixelsAndCompareWithExpected): >+ * DumpRenderTree/cg/PixelDumpSupportCG.h: >+ (BitmapContext::createByAdoptingBitmapAndContext): >+ (BitmapContext::~BitmapContext): >+ (BitmapContext::cgContext): >+ (BitmapContext::BitmapContext): >+ * DumpRenderTree/mac/DumpRenderTree.mm: >+ (shouldIgnoreWebCoreNodeLeaks): >+ (setDefaultsToConsistentValuesForTesting): >+ (crashHandler): >+ (initializeGlobalsFromCommandLineOptions): >+ (prepareConsistentTestingEnvironment): >+ (dumpRenderTree): >+ (sizeWebViewForCurrentTest): >+ (dump): >+ (runTest): >+ * DumpRenderTree/mac/PixelDumpSupportMac.mm: >+ (restoreMainDisplayColorProfile): >+ (setupMainDisplayColorProfile): >+ (createBitmapContextFromWebView): >+ * DumpRenderTree/win/DumpRenderTree.cpp: >+ (dump): >+ (runTest): >+ * DumpRenderTree/win/PixelDumpSupportWin.cpp: >+ (getBitmapContextFromWebView): >+ * Scripts/run-webkit-tests: >+ > 2008-10-22 Brady Eidson <beidson@apple.com> > > Reviewed by Adam Roben >diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj >index 348069c..bfc7500 100644 >--- a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj >+++ b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj >@@ -33,6 +33,7 @@ > 1AC6C8490D07638600CD3161 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C77F0D07589B00CD3161 /* main.cpp */; }; > 1AC6C84A0D07638600CD3161 /* PluginObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */; }; > 1AC6C84B0D07638600CD3161 /* TestObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C7810D07589B00CD3161 /* TestObject.cpp */; }; >+ 23BCB8900EA57623003C6289 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23BCB88F0EA57623003C6289 /* OpenGL.framework */; }; > 9340994C08540CAE007F3BC8 /* DumpRenderTreePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */; }; > 9340995108540CAE007F3BC8 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9335435F03D75502008635CE /* WebKit.framework */; }; > A817090008B163EF00CCB9FB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A84F608908B136DA00E9745F /* Cocoa.framework */; }; >@@ -131,6 +132,7 @@ > 1AC6C77F0D07589B00CD3161 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; }; > 1AC6C7800D07589B00CD3161 /* PluginObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginObject.cpp; sourceTree = "<group>"; }; > 1AC6C7810D07589B00CD3161 /* TestObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestObject.cpp; sourceTree = "<group>"; }; >+ 23BCB88F0EA57623003C6289 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; }; > 32A70AAB03705E1F00C91783 /* DumpRenderTreePrefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumpRenderTreePrefix.h; sourceTree = "<group>"; }; > 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher100.ttf; path = fonts/WebKitWeightWatcher100.ttf; sourceTree = "<group>"; }; > 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher200.ttf; path = fonts/WebKitWeightWatcher200.ttf; sourceTree = "<group>"; }; >@@ -234,6 +236,7 @@ > A84F608A08B136DA00E9745F /* Cocoa.framework in Frameworks */, > A817090408B164D300CCB9FB /* JavaScriptCore.framework in Frameworks */, > 9340995108540CAE007F3BC8 /* WebKit.framework in Frameworks */, >+ 23BCB8900EA57623003C6289 /* OpenGL.framework in Frameworks */, > ); > runOnlyForDeploymentPostprocessing = 0; > }; >@@ -375,6 +378,7 @@ > A817090308B164D300CCB9FB /* JavaScriptCore.framework */, > B5A752A108AF5D1F00138E45 /* QuartzCore.framework */, > 9335435F03D75502008635CE /* WebKit.framework */, >+ 23BCB88F0EA57623003C6289 /* OpenGL.framework */, > ); > name = Frameworks; > sourceTree = "<group>"; >diff --git a/WebKitTools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h b/WebKitTools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h >new file mode 100644 >index 0000000..aafd1a2 >--- /dev/null >+++ b/WebKitTools/DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h >@@ -0,0 +1 @@ >+#include <JavaScriptCore/PassRefPtr.h> >diff --git a/WebKitTools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h b/WebKitTools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h >new file mode 100644 >index 0000000..0ff6213 >--- /dev/null >+++ b/WebKitTools/DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h >@@ -0,0 +1 @@ >+#include <JavaScriptCore/RefPtr.h> >diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/LayoutTestController.cpp >index 6c6a273..aa717f4 100644 >--- a/WebKitTools/DumpRenderTree/LayoutTestController.cpp >+++ b/WebKitTools/DumpRenderTree/LayoutTestController.cpp >@@ -34,7 +34,7 @@ > #include <wtf/Assertions.h> > #include <wtf/MathExtras.h> > >-LayoutTestController::LayoutTestController(bool testRepaintDefault, bool testRepaintSweepHorizontallyDefault) >+LayoutTestController::LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash) > : m_dumpAsText(false) > , m_dumpAsPDF(false) > , m_dumpBackForwardList(false) >@@ -54,11 +54,14 @@ LayoutTestController::LayoutTestController(bool testRepaintDefault, bool testRep > , m_canOpenWindows(false) > , m_closeRemainingWindowsWhenComplete(true) > , m_stopProvisionalFrameLoads(false) >- , m_testRepaint(testRepaintDefault) >- , m_testRepaintSweepHorizontally(testRepaintSweepHorizontallyDefault) >+ , m_testOnscreen(false) >+ , m_testRepaint(false) >+ , m_testRepaintSweepHorizontally(false) > , m_waitToDump(false) > , m_windowIsKey(true) > , m_globalFlag(false) >+ , m_testPathOrURL(testPathOrURL) >+ , m_expectedPixelHash(expectedPixelHash) > { > } > >@@ -205,6 +208,13 @@ static JSValueRef setCloseRemainingWindowsWhenCompleteCallback(JSContextRef cont > return JSValueMakeUndefined(context); > } > >+static JSValueRef testOnscreenCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) >+{ >+ LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); >+ controller->setTestOnscreen(true); >+ return JSValueMakeUndefined(context); >+} >+ > static JSValueRef testRepaintCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) > { > LayoutTestController* controller = reinterpret_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); >@@ -745,6 +755,7 @@ JSStaticFunction* LayoutTestController::staticFunctions() > { "setUserStyleSheetEnabled", setUserStyleSheetEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, > { "setUserStyleSheetLocation", setUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, > { "setWindowIsKey", setWindowIsKeyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, >+ { "testOnscreen", testOnscreenCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, > { "testRepaint", testRepaintCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, > { "waitUntilDone", waitUntilDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, > { "windowCount", windowCountCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, >diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.h b/WebKitTools/DumpRenderTree/LayoutTestController.h >index 8e33e09..649db7a 100644 >--- a/WebKitTools/DumpRenderTree/LayoutTestController.h >+++ b/WebKitTools/DumpRenderTree/LayoutTestController.h >@@ -31,10 +31,11 @@ > > #include <JavaScriptCore/JSObjectRef.h> > #include <wtf/RefCounted.h> >+#include <string> > > class LayoutTestController : public RefCounted<LayoutTestController> { > public: >- LayoutTestController(bool testRepaintDefault, bool testRepaintSweepHorizontallyDefault); >+ LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash); > ~LayoutTestController(); > > void makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception); >@@ -130,6 +131,9 @@ public: > bool stopProvisionalFrameLoads() const { return m_stopProvisionalFrameLoads; } > void setStopProvisionalFrameLoads(bool stopProvisionalFrameLoads) { m_stopProvisionalFrameLoads = stopProvisionalFrameLoads; } > >+ bool testOnscreen() const { return m_testOnscreen; } >+ void setTestOnscreen(bool testOnscreen) { m_testOnscreen = testOnscreen; } >+ > bool testRepaint() const { return m_testRepaint; } > void setTestRepaint(bool testRepaint) { m_testRepaint = testRepaint; } > >@@ -144,7 +148,10 @@ public: > > bool globalFlag() const { return m_globalFlag; } > void setGlobalFlag(bool globalFlag) { m_globalFlag = globalFlag; } >- >+ >+ const std::string& testPathOrURL() const { return m_testPathOrURL; } >+ const std::string& expectedPixelHash() const { return m_expectedPixelHash; } >+ > private: > bool m_dumpAsText; > bool m_dumpAsPDF; >@@ -165,6 +172,7 @@ private: > bool m_canOpenWindows; > bool m_closeRemainingWindowsWhenComplete; > bool m_stopProvisionalFrameLoads; >+ bool m_testOnscreen; > bool m_testRepaint; > bool m_testRepaintSweepHorizontally; > bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called. >@@ -172,6 +180,9 @@ private: > > bool m_globalFlag; > >+ std::string m_testPathOrURL; >+ std::string m_expectedPixelHash; // empty string if no hash >+ > static JSClassRef getJSClass(); > static JSStaticValue* staticValues(); > static JSStaticFunction* staticFunctions(); >diff --git a/WebKitTools/DumpRenderTree/PixelDumpSupport.h b/WebKitTools/DumpRenderTree/PixelDumpSupport.h >index 3214d04..d4f8948 100644 >--- a/WebKitTools/DumpRenderTree/PixelDumpSupport.h >+++ b/WebKitTools/DumpRenderTree/PixelDumpSupport.h >@@ -29,12 +29,18 @@ > #ifndef PixelDumpSupport_h > #define PixelDumpSupport_h > >-void dumpWebViewAsPixelsAndCompareWithExpected(const char* currentTest, bool forceAllTestsToDumpPixels); >+#include <string> >+ >+void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash); >+ >+#if PLATFORM(MAC) > > // Can be used as a signal handler >-void restoreColorSpace(int ignored); >+void restoreMainDisplayColorProfile(int ignored); >+ >+// May change your color space, requiring a call to restoreMainDisplayColorProfile >+void setupMainDisplayColorProfile(); > >-// May change your color space, requiring a call to restoreColorSpace >-void initializeColorSpaceAndScreeBufferForPixelTests(); >+#endif > > #endif // PixelDumpSupport_h >diff --git a/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp b/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp >index c393913..d80f052 100644 >--- a/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp >+++ b/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp >@@ -36,6 +36,7 @@ > #if PLATFORM(WIN) > #include <fcntl.h> > #include <io.h> >+#include <wtf/MathExtras.h> > #endif > > #if PLATFORM(MAC) >@@ -54,6 +55,10 @@ typedef float CGFloat; > using namespace std; > > #if PLATFORM(WIN) >+static inline float strtof(const char *nptr, char **endptr) >+{ >+ return strtod(nptr, endptr); >+} > static const CFStringRef kUTTypePNG = CFSTR("public.png"); > #endif > >@@ -72,99 +77,99 @@ static RetainPtr<CGImageRef> createImageFromStdin(int bytesRemaining) > return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateWithPNGDataProvider(dataProvider.get(), 0, false, kCGRenderingIntentDefault)); > } > >-// Generates an RGBA8 bitmap in the reference image colorspace containing the differences between the 2 images >-static RetainPtr<CGContextRef> createDifferenceBitmap(CGImageRef testImage, CGImageRef referenceImage) >+static void releaseMallocBuffer(void* info, const void* data, size_t size) > { >- // we must have both images to take diff >- if (!testImage || !referenceImage) { >- fprintf(stderr, "test or reference image is missing!"); >- return 0; >- } >- >- // we must have both images be the same dimensions >- if ((CGImageGetWidth(testImage) != CGImageGetWidth(referenceImage)) || (CGImageGetHeight(testImage) != CGImageGetHeight(referenceImage))) { >- fprintf(stderr, "test and reference image dimensions don't match!"); >- return 0; >- } >- >- // we must have both images in the same colorspace >- if (!CFEqual(CGImageGetColorSpace(testImage), CGImageGetColorSpace(referenceImage))) { >- fprintf(stderr, "test and reference image colorspaces don't match!"); >- return 0; >- } >- >- static CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); >- size_t rowBytes = (4 * CGImageGetWidth(referenceImage) + 63) & ~63; // Use a multiple of 64 bytes to improve CG performance >- CFDataSetLength(data, CGImageGetHeight(referenceImage) * rowBytes); >- RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(CFDataGetMutableBytePtr(data), CGImageGetWidth(referenceImage), CGImageGetHeight(referenceImage), 8, rowBytes, CGImageGetColorSpace(referenceImage), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big)); >- >- CGContextSetBlendMode(context.get(), kCGBlendModeNormal); >- CGContextDrawImage(context.get(), CGRectMake(0, 0, static_cast<CGFloat>(CGImageGetWidth(testImage)), static_cast<CGFloat>(CGImageGetHeight(testImage))), testImage); >- CGContextSetBlendMode(context.get(), kCGBlendModeDifference); >- CGContextDrawImage(context.get(), CGRectMake(0, 0, static_cast<CGFloat>(CGImageGetWidth(referenceImage)), static_cast<CGFloat>(CGImageGetHeight(referenceImage))), referenceImage); >- >- return context; >+ free((void*)data); > } > >-// Counts the number of non-black pixels, and returns the percentage of non-black pixels to total pixels in the image. >-static float computePercentageDifferent(CGContextRef diffBitmap, unsigned threshold) >+static RetainPtr<CGImageRef> createDifferenceImage(CGImageRef baseImage, CGImageRef testImage, float& difference) > { >- // if diffBitmap is nil, then there was an error, and it didn't match. >- if (!diffBitmap) >- return 100.0f; >- >- size_t pixelsHigh = CGBitmapContextGetHeight(diffBitmap); >- size_t pixelsWide = CGBitmapContextGetWidth(diffBitmap); >- size_t bytesPerRow = CGBitmapContextGetBytesPerRow(diffBitmap); >- unsigned char* pixelRowData = static_cast<unsigned char*>(CGBitmapContextGetData(diffBitmap)); >- unsigned differences = 0; >- >- for (unsigned row = 0; row < pixelsHigh; row++) { >- for (unsigned col = 0; col < (pixelsWide * 4); col += 4) { >- unsigned char* red = pixelRowData + col; >- unsigned char* green = red + 1; >- unsigned char* blue = red + 2; >- unsigned distance = *red + *green + *blue; >- if (distance > threshold) { >- differences++; >- // shift the pixels towards white to make them more visible >- *red = static_cast<unsigned char>(min(UCHAR_MAX, *red + 100)); >- *green = static_cast<unsigned char>(min(UCHAR_MAX, *green + 100)); >- *blue = static_cast<unsigned char>(min(UCHAR_MAX, *blue + 100)); >+ static RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); >+ RetainPtr<CGImageRef> diffImage; >+ >+ size_t width = CGImageGetWidth(baseImage); >+ size_t height = CGImageGetHeight(baseImage); >+ size_t rowBytes = width * 4; >+ >+ // Draw base image in bitmap context >+ void* baseBuffer = calloc(height, rowBytes); >+ CGContextRef baseContext = CGBitmapContextCreate(baseBuffer, width, height, 8, rowBytes, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); >+ CGContextDrawImage(baseContext, CGRectMake(0, 0, width, height), baseImage); >+ CGContextRelease(baseContext); >+ >+ // Draw test image in bitmap context >+ void* buffer = calloc(height, rowBytes); >+ CGContextRef context = CGBitmapContextCreate(buffer, width, height, 8, rowBytes, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); >+ CGContextDrawImage(context, CGRectMake(0, 0, width, height), testImage); >+ CGContextRelease(context); >+ >+ // Compare the content of the 2 bitmaps >+ void* diffBuffer = malloc(width * height); >+ float count = 0.0f; >+ float sum = 0.0f; >+ float maxDistance = 0.0f; >+ unsigned char* basePixel = (unsigned char*)baseBuffer; >+ unsigned char* pixel = (unsigned char*)buffer; >+ unsigned char* diff = (unsigned char*)diffBuffer; >+ for (size_t y = 0; y < height; ++y) { >+ for (size_t x = 0; x < width; ++x) { >+ float red = (pixel[0] - basePixel[0]) / max<float>(255 - basePixel[0], basePixel[0]); >+ float green = (pixel[1] - basePixel[1]) / max<float>(255 - basePixel[1], basePixel[1]); >+ float blue = (pixel[2] - basePixel[2]) / max<float>(255 - basePixel[2], basePixel[2]); >+ float alpha = (pixel[3] - basePixel[3]) / max<float>(255 - basePixel[3], basePixel[3]); >+ float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; >+ >+ *diff++ = (unsigned char)(distance * 255.0f); >+ >+ if (distance >= 1.0f / 255.0f) { >+ count += 1.0f; >+ sum += distance; >+ if (distance > maxDistance) >+ maxDistance = distance; > } >+ >+ basePixel += 4; >+ pixel += 4; > } >- pixelRowData += bytesPerRow; > } >- >- float totalPixels = static_cast<float>(pixelsHigh * pixelsWide); >- return (differences * 100.f) / totalPixels; >+ >+ // 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 >+ if (count > 0.0f) >+ difference = 100.0f * sum / (height * width); >+ else >+ difference = 0.0f; >+ >+ // Generate a normalized diff image if there is any difference >+ if (difference > 0.0f) { >+ if (maxDistance < 1.0f) { >+ diff = (unsigned char*)diffBuffer; >+ for(size_t p = 0; p < height * width; ++p) >+ diff[p] = diff[p] / maxDistance; >+ } >+ >+ CGDataProviderRef provider = CGDataProviderCreateWithData(0, diffBuffer, width * height, releaseMallocBuffer); >+ CGColorSpaceRef diffColorspace = CGColorSpaceCreateDeviceGray(); >+ diffImage.adoptCF(CGImageCreate(width, height, 8, 8, width, diffColorspace, 0, provider, 0, false, kCGRenderingIntentDefault)); >+ CGColorSpaceRelease(diffColorspace); >+ CGDataProviderRelease(provider); >+ } >+ else >+ free(diffBuffer); >+ >+ // Destroy drawing buffers >+ if (buffer) >+ free(buffer); >+ if (baseBuffer) >+ free(baseBuffer); >+ >+ return diffImage; > } > >-static void compareImages(CGImageRef testImage, CGImageRef referenceImage, unsigned threshold) >+static inline bool imageHasAlpha(CGImageRef image) > { >- // prepare the difference blend to check for pixel variations >- RetainPtr<CGContextRef> diffBitmap = createDifferenceBitmap(testImage, referenceImage); >- >- float percentage = computePercentageDifferent(diffBitmap.get(), threshold); >- >- percentage = (float)((int)(percentage * 100.0f)) / 100.0f; // round to 2 decimal places >- >- // send message to let them know if an image was wrong >- if (percentage > 0.0f) { >- // since the diff might actually show something, send it to stdout >- if (diffBitmap) { >- RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(diffBitmap.get())); >- 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()); >- printf("Content-Length: %lu\n", CFDataGetLength(imageData.get())); >- fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); >- } >- >- fprintf(stdout, "diff: %01.2f%% failed\n", percentage); >- } else >- fprintf(stdout, "diff: %01.2f%% passed\n", percentage); >+ CGImageAlphaInfo info = CGImageGetAlphaInfo(image); >+ >+ return (info >= kCGImageAlphaPremultipliedLast) && (info <= kCGImageAlphaFirst); > } > > int main(int argc, const char* argv[]) >@@ -174,13 +179,13 @@ int main(int argc, const char* argv[]) > _setmode(1, _O_BINARY); > #endif > >- unsigned threshold = 0; >+ float tolerance = 0.0f; > > for (int i = 1; i < argc; ++i) { >- if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--threshold")) { >+ if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) { > if (i >= argc - 1) > exit(1); >- threshold = strtol(argv[i + 1], 0, 0); >+ tolerance = strtof(argv[i + 1], 0); > ++i; > continue; > } >@@ -209,7 +214,35 @@ int main(int argc, const char* argv[]) > } > > if (actualImage && baselineImage) { >- compareImages(actualImage.get(), baselineImage.get(), threshold); >+ RetainPtr<CGImageRef> diffImage; >+ float difference = 100.0f; >+ >+ if ((CGImageGetWidth(actualImage.get()) == CGImageGetWidth(baselineImage.get())) && (CGImageGetHeight(actualImage.get()) == CGImageGetHeight(baselineImage.get())) && (imageHasAlpha(actualImage.get()) == imageHasAlpha(baselineImage.get()))) { >+ diffImage = createDifferenceImage(actualImage.get(), baselineImage.get(), difference); // difference is passed by reference >+ if (difference <= tolerance) >+ difference = 0.0f; >+ else { >+ difference = roundf(difference * 100.0f) / 100.0f; >+ difference = max(difference, 0.01f); // round to 2 decimal places >+ } >+ } >+ else >+ fputs("error, test and reference image have different properties.\n", stderr); >+ >+ if (difference > 0.0f) { >+ if (diffImage) { >+ RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); >+ RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0)); >+ CGImageDestinationAddImage(imageDest.get(), diffImage.get(), 0); >+ CGImageDestinationFinalize(imageDest.get()); >+ printf("Content-Length: %lu\n", CFDataGetLength(imageData.get())); >+ fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); >+ } >+ >+ fprintf(stdout, "diff: %01.2f%% failed\n", difference); >+ } else >+ fprintf(stdout, "diff: %01.2f%% passed\n", difference); >+ > actualImage = 0; > baselineImage = 0; > } >diff --git a/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.cpp b/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.cpp >index 260a94e..2320e19 100644 >--- a/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.cpp >+++ b/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.cpp >@@ -34,7 +34,10 @@ > #include "DumpRenderTree.h" > #include "LayoutTestController.h" > #include <ImageIO/CGImageDestination.h> >+#include <algorithm> >+#include <ctype.h> > #include <wtf/Assertions.h> >+#include <wtf/RefPtr.h> > #include <wtf/RetainPtr.h> > #include <wtf/StringExtras.h> > >@@ -63,66 +66,69 @@ static void printPNG(CGImageRef image) > fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); > } > >-static void getMD5HashStringForBitmap(CGContextRef bitmap, char string[33]) >+static void computeMD5HashStringForBitmapContext(CGContextRef bitmapContext, char hashString[33]) > { >- MD5_CTX md5Context; >- unsigned char hash[16]; >- >- size_t bitsPerPixel = CGBitmapContextGetBitsPerPixel(bitmap); >- ASSERT(bitsPerPixel == 32); // ImageDiff assumes 32 bit RGBA, we must as well. >- size_t bytesPerPixel = bitsPerPixel / 8; >- size_t pixelsHigh = CGBitmapContextGetHeight(bitmap); >- size_t pixelsWide = CGBitmapContextGetWidth(bitmap); >- size_t bytesPerRow = CGBitmapContextGetBytesPerRow(bitmap); >- ASSERT(bytesPerRow >= (pixelsWide * bytesPerPixel)); >+ 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_CTX md5Context; > MD5_Init(&md5Context); >- unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmap)); >- for (unsigned row = 0; row < pixelsHigh; row++) { >- MD5_Update(&md5Context, bitmapData, static_cast<unsigned>(pixelsWide * bytesPerPixel)); >- bitmapData += bytesPerRow; >+ unsigned char* bitmapData = static_cast<unsigned char*>(CGBitmapContextGetData(bitmapContext)); >+#if PLATFORM(MAC) >+ if ((CGBitmapContextGetBitmapInfo(bitmapContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Big) { >+ for (unsigned row = 0; row < pixelsHigh; row++) { >+ uint32_t buffer[pixelsWide]; >+ for (unsigned column = 0; column < pixelsWide; column++) >+ buffer[column] = OSReadLittleInt32(bitmapData, 4 * column); >+ MD5_Update(&md5Context, buffer, 4 * pixelsWide); >+ bitmapData += bytesPerRow; >+ } >+ } else >+#endif >+ { >+ for (unsigned row = 0; row < pixelsHigh; row++) { >+ MD5_Update(&md5Context, bitmapData, 4 * pixelsWide); >+ bitmapData += bytesPerRow; >+ } > } >+ unsigned char hash[16]; > MD5_Final(hash, &md5Context); > >- string[0] = '\0'; >+ hashString[0] = '\0'; > for (int i = 0; i < 16; i++) >- snprintf(string, 33, "%s%02x", string, hash[i]); >-} >- >-void drawSelectionRect(CGContextRef context, const CGRect& rect) >-{ >- CGContextSaveGState(context); >- CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0); >- CGContextStrokeRect(context, rect); >- CGContextRestoreGState(context); >+ snprintf(hashString, 33, "%s%02x", hashString, hash[i]); > } > >-void dumpWebViewAsPixelsAndCompareWithExpected(const char* /*currentTest*/, bool /*forceAllTestsToDumpPixels*/) >+void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash) > { >- RetainPtr<CGContextRef> context = getBitmapContextFromWebView(); >- >+ RefPtr<BitmapContext> context; >+ > #if PLATFORM(MAC) >- if (gLayoutTestController->testRepaint()) >- repaintWebView(context.get(), gLayoutTestController->testRepaintSweepHorizontally()); >- else >- paintWebView(context.get()); >- >- if (gLayoutTestController->dumpSelectionRect()) >- drawSelectionRect(context.get(), getSelectionRect()); >+ context = createBitmapContextFromWebView(gLayoutTestController->testOnscreen(), gLayoutTestController->testRepaint(), gLayoutTestController->testRepaintSweepHorizontally(), gLayoutTestController->dumpSelectionRect()); > #endif >- >- // Compute the actual hash to compare to the expected image's hash. >+ ASSERT(context); >+ >+ // Compute the hash of the bitmap context pixels > char actualHash[33]; >- getMD5HashStringForBitmap(context.get(), actualHash); >+ computeMD5HashStringForBitmapContext(context->cgContext(), actualHash); > printf("\nActualHash: %s\n", actualHash); >- >- // FIXME: We should compare the actualHash to the expected hash here and >- // only set dumpImage to true if they don't match, but DRT doesn't have >- // enough information currently to find the expected checksum file. >+ >+ // Check the computed hash against the expected one and dump image on mismatch > bool dumpImage = true; >- >+ if (expectedHash.length() > 0) { >+ ASSERT(expectedHash.length() == 32); >+ >+ printf("\nExpectedHash: %s\n", expectedHash.c_str()); >+ >+ if (expectedHash == actualHash) // FIXME: do case insensitive compare >+ dumpImage = false; >+ } >+ > if (dumpImage) { >- RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context.get())); >+ RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context->cgContext())); > printPNG(image.get()); > } > } >diff --git a/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.h b/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.h >index 0abdea6..3272711 100644 >--- a/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.h >+++ b/WebKitTools/DumpRenderTree/cg/PixelDumpSupportCG.h >@@ -31,25 +31,50 @@ > #ifndef PixelDumpSupportCG_h > #define PixelDumpSupportCG_h > >+#include <wtf/PassRefPtr.h> >+#include <wtf/RefCounted.h> > #include <wtf/RetainPtr.h> > >-#ifndef CGFLOAT_DEFINED >-#ifdef __LP64__ >-typedef double CGFloat; >-#else >-typedef float CGFloat; >+typedef struct CGContext* CGContextRef; >+ >+#if PLATFORM(MAC) >+typedef void* BitmapContextBacking; >+#elif PLATFORM(WIN) >+typedef HBITMAP BitmapContextBacking; > #endif >-#define CGFLOAT_DEFINED 1 >+ >+class BitmapContext : public RefCounted<BitmapContext> { >+public: >+ static PassRefPtr<BitmapContext> createByAdoptingBitmapAndContext(BitmapContextBacking backing, CGContextRef context) >+ { >+ return adoptRef(new BitmapContext(backing, context)); >+ } >+ >+ ~BitmapContext() >+ { >+ if (m_backing) >+#if PLATFORM(MAC) >+ free(m_backing); >+#elif PLATFORM(WIN) >+ DeleteObject(m_backing); > #endif >+ } > >-typedef struct CGContext* CGContextRef; >-struct CGRect; >+ CGContextRef cgContext() const { return m_context.get(); } >+ >+private: >+ >+ BitmapContext(BitmapContextBacking backing, CGContextRef context) >+ : m_backing(backing) >+ , m_context(AdoptCF, context) >+ { >+ } >+ >+ BitmapContextBacking m_backing; >+ RetainPtr<CGContextRef> m_context; > >-RetainPtr<CGContextRef> getBitmapContextFromWebView(); >-CGRect getSelectionRect(); >+}; > >-void paintWebView(CGContextRef); >-void repaintWebView(CGContextRef context, bool horizontal); >-void drawSelectionRect(CGContextRef, const CGRect&); >+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect); > > #endif // PixelDumpSupportCG_h >diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm >index bece906..596bf69 100644 >--- a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm >+++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm >@@ -75,10 +75,12 @@ > #import <wtf/RetainPtr.h> > #import <wtf/OwnPtr.h> > >+using namespace std; >+ > @interface DumpRenderTreeEvent : NSEvent > @end > >-static void runTest(const char *pathOrURL); >+static void runTest(const string& testPathOrURL); > > // Deciding when it's OK to dump out the state is a bit tricky. All these must be true: > // - There is no load in progress >@@ -111,14 +113,10 @@ static ResourceLoadDelegate *resourceLoadDelegate; > PolicyDelegate *policyDelegate; > > static int dumpPixels; >-static int dumpAllPixels; > static int threaded; >-static int testRepaintDefault; >-static int repaintSweepHorizontallyDefault; > static int dumpTree = YES; > static int forceComplexText; > static BOOL printSeparators; >-static NSString *currentTest = nil; > static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; > > static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous test >@@ -181,21 +179,21 @@ void setPersistentUserStyleSheetLocation(CFStringRef url) > persistentUserStyleSheetLocation = url; > } > >-static BOOL shouldIgnoreWebCoreNodeLeaks(CFStringRef URLString) >+static bool shouldIgnoreWebCoreNodeLeaks(const string& URLString) > { >- static CFStringRef const ignoreSet[] = { >+ static char* const ignoreSet[] = { > // Keeping this infrastructure around in case we ever need it again. > }; >- static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(CFStringRef); >+ static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(char*); > > for (int i = 0; i < ignoreSetCount; i++) { >- CFStringRef ignoreString = ignoreSet[i]; >- CFRange range = CFRangeMake(0, CFStringGetLength(URLString)); >- CFOptionFlags flags = kCFCompareAnchored | kCFCompareBackwards | kCFCompareCaseInsensitive; >- if (CFStringFindWithOptions(URLString, ignoreString, range, flags, NULL)) >- return YES; >+ // FIXME: ignore case >+ string curIgnore(ignoreSet[i]); >+ // Match at the end of the URLString >+ if (!URLString.compare(URLString.length() - curIgnore.length(), curIgnore.length(), curIgnore)) >+ return true; > } >- return NO; >+ return false; > } > > static void activateFonts() >@@ -307,13 +305,13 @@ void testStringByEvaluatingJavaScriptFromString() > static void setDefaultsToConsistentValuesForTesting() > { > // Give some clear to undocumented defaults values >- static const int MediumFontSmoothing = 2; >+ static const int NoFontSmoothing = 0; > static const int BlueTintedAppearance = 1; > > NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; > [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"]; > [defaults setInteger:4 forKey:@"AppleAntiAliasingThreshold"]; // smallest font size to CG should perform antialiasing on >- [defaults setInteger:MediumFontSmoothing forKey:@"AppleFontSmoothing"]; >+ [defaults setInteger:NoFontSmoothing forKey:@"AppleFontSmoothing"]; > [defaults setInteger:BlueTintedAppearance forKey:@"AppleAquaColorVariant"]; > [defaults setObject:@"0.709800 0.835300 1.000000" forKey:@"AppleHighlightColor"]; > [defaults setObject:@"0.500000 0.500000 0.500000" forKey:@"AppleOtherHighlightColor"]; >@@ -350,7 +348,7 @@ static void crashHandler(int sig) > char *signalName = strsignal(sig); > write(STDERR_FILENO, signalName, strlen(signalName)); > write(STDERR_FILENO, "\n", 1); >- restoreColorSpace(0); >+ restoreMainDisplayColorProfile(0); > exit(128 + sig); > } > >@@ -399,11 +397,8 @@ static void releaseGlobalControllers() > static void initializeGlobalsFromCommandLineOptions(int argc, const char *argv[]) > { > struct option options[] = { >- {"dump-all-pixels", no_argument, &dumpAllPixels, YES}, >- {"horizontal-sweep", no_argument, &repaintSweepHorizontallyDefault, YES}, > {"notree", no_argument, &dumpTree, NO}, > {"pixel-tests", no_argument, &dumpPixels, YES}, >- {"repaint", no_argument, &testRepaintDefault, YES}, > {"tree", no_argument, &dumpTree, YES}, > {"threaded", no_argument, &threaded, YES}, > {"complex-text", no_argument, &forceComplexText, YES}, >@@ -460,7 +455,7 @@ static void prepareConsistentTestingEnvironment() > activateFonts(); > > if (dumpPixels) >- initializeColorSpaceAndScreeBufferForPixelTests(); >+ setupMainDisplayColorProfile(); > allocateGlobalControllers(); > > makeLargeMallocFailSilently(); >@@ -526,7 +521,7 @@ void dumpRenderTree(int argc, const char *argv[]) > } > > if (dumpPixels) >- restoreColorSpace(0); >+ restoreMainDisplayColorProfile(0); > } > > int main(int argc, const char *argv[]) >@@ -821,7 +816,7 @@ static void dumpBackForwardListForWebView(WebView *view) > static void sizeWebViewForCurrentTest() > { > // W3C SVG tests expect to be 480x360 >- bool isSVGW3CTest = ([currentTest rangeOfString:@"svg/W3C-SVG-1.1"].length); >+ bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg/W3C-SVG-1.1") != string::npos); > if (isSVGW3CTest) > [[mainFrame webView] setFrameSize:NSMakeSize(480, 360)]; > else >@@ -915,8 +910,8 @@ void dump() > } > } > >- if (dumpAllPixels || (dumpPixels && !dumpAsText)) >- dumpWebViewAsPixelsAndCompareWithExpected([currentTest UTF8String], dumpAllPixels); >+ if (dumpPixels && !dumpAsText) >+ dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); > > puts("#EOF"); // terminate the (possibly empty) pixels block > >@@ -931,16 +926,6 @@ static bool shouldLogFrameLoadDelegates(const char *pathOrURL) > return strstr(pathOrURL, "loading/"); > } > >-static CFURLRef createCFURLFromPathOrURL(CFStringRef pathOrURLString) >-{ >- CFURLRef URL; >- if (CFStringHasPrefix(pathOrURLString, CFSTR("http://")) || CFStringHasPrefix(pathOrURLString, CFSTR("https://"))) >- URL = CFURLCreateWithString(NULL, pathOrURLString, NULL); >- else >- URL = CFURLCreateWithFileSystemPath(NULL, pathOrURLString, kCFURLPOSIXPathStyle, FALSE); >- return URL; >-} >- > static void resetWebViewToConsistentStateBeforeTesting() > { > WebView *webView = [mainFrame webView]; >@@ -969,30 +954,47 @@ static void resetWebViewToConsistentStateBeforeTesting() > [WebView _setUsesTestModeFocusRingColor:YES]; > } > >-static void runTest(const char *pathOrURL) >+static void runTest(const string& testPathOrURL) > { >- CFStringRef pathOrURLString = CFStringCreateWithCString(NULL, pathOrURL, kCFStringEncodingUTF8); >+ ASSERT(!testPathOrURL.empty()); >+ >+ // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. >+ string pathOrURL(testPathOrURL); >+ string expectedPixelHash; >+ >+ size_t separatorPos = pathOrURL.find("'"); >+ if (separatorPos != string::npos) { >+ pathOrURL = string(testPathOrURL, 0, separatorPos); >+ expectedPixelHash = string(testPathOrURL, separatorPos + 1); >+ } >+ >+ NSString *pathOrURLString = [NSString stringWithUTF8String:pathOrURL.c_str()]; > if (!pathOrURLString) { >- fprintf(stderr, "Failed to parse filename as UTF-8: %s\n", pathOrURL); >+ fprintf(stderr, "Failed to parse \"%s\" as UTF-8\n", pathOrURL.c_str()); > return; > } > >- CFURLRef URL = createCFURLFromPathOrURL(pathOrURLString); >- if (!URL) { >- CFRelease(pathOrURLString); >- fprintf(stderr, "Can't turn %s into a CFURL\n", pathOrURL); >+ NSURL *url; >+ if ([pathOrURLString hasPrefix:@"http://"] || [pathOrURLString hasPrefix:@"https://"]) >+ url = [NSURL URLWithString:pathOrURLString]; >+ else >+ url = [NSURL fileURLWithPath:pathOrURLString]; >+ if (!url) { >+ fprintf(stderr, "Failed to parse \"%s\" as a URL\n", pathOrURL.c_str()); > return; > } > >+ const string testURL([[url absoluteString] UTF8String]); >+ > resetWebViewToConsistentStateBeforeTesting(); > >- gLayoutTestController = new LayoutTestController(testRepaintDefault, repaintSweepHorizontallyDefault); >+ gLayoutTestController = new LayoutTestController(testURL, expectedPixelHash); > topLoadingFrame = nil; > done = NO; > > if (disallowedURLs) > CFSetRemoveAllValues(disallowedURLs); >- if (shouldLogFrameLoadDelegates(pathOrURL)) >+ if (shouldLogFrameLoadDelegates(pathOrURL.c_str())) > gLayoutTestController->setDumpFrameLoadCallbacks(true); > > if ([WebHistory optionalSharedHistory]) >@@ -1000,22 +1002,18 @@ static void runTest(const char *pathOrURL) > lastMousePosition = NSZeroPoint; > lastClickPosition = NSZeroPoint; > >- if (currentTest != nil) >- CFRelease(currentTest); >- currentTest = (NSString *)pathOrURLString; > [prevTestBFItem release]; > prevTestBFItem = [[[[mainFrame webView] backForwardList] currentItem] retain]; > > WorkQueue::shared()->clear(); > WorkQueue::shared()->setFrozen(false); > >- BOOL _shouldIgnoreWebCoreNodeLeaks = shouldIgnoreWebCoreNodeLeaks(CFURLGetString(URL)); >- if (_shouldIgnoreWebCoreNodeLeaks) >+ bool ignoreWebCoreNodeLeaks = shouldIgnoreWebCoreNodeLeaks(testURL); >+ if (ignoreWebCoreNodeLeaks) > [WebCoreStatistics startIgnoringWebCoreNodeLeaks]; > > NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; >- [mainFrame loadRequest:[NSURLRequest requestWithURL:(NSURL *)URL]]; >- CFRelease(URL); >+ [mainFrame loadRequest:[NSURLRequest requestWithURL:url]]; > [pool release]; > while (!done) { > pool = [[NSAutoreleasePool alloc] init]; >@@ -1058,7 +1056,7 @@ static void runTest(const char *pathOrURL) > gLayoutTestController->deref(); > gLayoutTestController = 0; > >- if (_shouldIgnoreWebCoreNodeLeaks) >+ if (ignoreWebCoreNodeLeaks) > [WebCoreStatistics stopIgnoringWebCoreNodeLeaks]; > } > >diff --git a/WebKitTools/DumpRenderTree/mac/PixelDumpSupportMac.mm b/WebKitTools/DumpRenderTree/mac/PixelDumpSupportMac.mm >index 9ddba31..eb29ffa 100644 >--- a/WebKitTools/DumpRenderTree/mac/PixelDumpSupportMac.mm >+++ b/WebKitTools/DumpRenderTree/mac/PixelDumpSupportMac.mm >@@ -34,153 +34,221 @@ > > #include "LayoutTestController.h" > #include <CoreGraphics/CGBitmapContext.h> >+#ifndef BUILDING_ON_LEOPARD >+#include <OpenGL/OpenGL.h> >+#include <OpenGL/CGLMacro.h> >+#endif > #include <wtf/Assertions.h> >-#include <wtf/RetainPtr.h> >+#include <wtf/RefPtr.h> > > #import <WebKit/WebDocumentPrivate.h> > #import <WebKit/WebKit.h> > >-static unsigned char* screenCaptureBuffer; >+// To ensure pixel tests consistency, we need to always render in the same colorspace. >+// Unfortunately, because of AppKit / WebKit constraints, we can't render directly in the colorspace of our choice. >+// This implies we have to temporarily change the profile of the main display to the colorspace we want to render into. >+// We also need to make sure the CGBitmapContext we return is in that same colorspace. > >-static bool changedColorProfile = false; >-static CMProfileLocation currentColorProfileLocation; >-static CGColorSpaceRef sharedColorSpace; >+#define PROFILE_PATH "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc" // FIXME: Should we be using "/System/Library/ColorSync/Profiles/sRGB Profile.icc"? > >-void restoreColorSpace(int ignored) >+static CMProfileLocation sInitialProfileLocation; // The locType field is initialized to 0 which is the same as cmNoProfileBase >+ >+void restoreMainDisplayColorProfile(int ignored) > { > // This is used as a signal handler, and thus the calls into ColorSync are unsafe > // But we might as well try to restore the user's color profile, we're going down anyway... >- if (changedColorProfile) { >- CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; >- int error = CMSetDeviceProfile(cmDisplayDeviceClass, cmDefaultDeviceID, &scope, cmDefaultProfileID, ¤tColorProfileLocation); >+ if (sInitialProfileLocation.locType != cmNoProfileBase) { >+ const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; >+ int error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &sInitialProfileLocation); > if (error) >- fprintf(stderr, "Failed to retore previous color profile! You may need to open System Preferences : Displays : Color and manually restore your color settings. (Error: %i)", error); >- changedColorProfile = false; >+ fprintf(stderr, "Failed to restore initial color profile for main display! Open System Preferences > Displays > Color and manually re-select the profile. (Error: %i)", error); >+ sInitialProfileLocation.locType = cmNoProfileBase; > } > } > >-static void failedGettingCurrentProfile(int error) >+void setupMainDisplayColorProfile() > { >- fprintf(stderr, "Failed to get current color profile. I will not be able to restore your current profile, thus I'm not changing it. Many pixel tests may fail as a result. (Error: %i)\n", error); >-} >- >-static void setDefaultColorProfileToRGB() >-{ >- CMProfileRef genericProfile = (CMProfileRef)[[NSColorSpace genericRGBColorSpace] colorSyncProfile]; >- CMProfileLocation genericProfileLocation; >- UInt32 locationSize = sizeof(genericProfileLocation); >- int error = NCMGetProfileLocation(genericProfile, &genericProfileLocation, &locationSize); >- if (error) { >- failedGettingCurrentProfile(error); >- return; >+ const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; >+ int error; >+ >+ CMProfileRef profile = 0; >+ error = CMGetProfileByAVID((CMDisplayIDType)kCGDirectMainDisplay, &profile); >+ if (!error) { >+ UInt32 size = sizeof(CMProfileLocation); >+ error = NCMGetProfileLocation(profile, &sInitialProfileLocation, &size); >+ CMCloseProfile(profile); > } >- >- CMProfileLocation previousProfileLocation; >- error = CMGetDeviceProfile(cmDisplayDeviceClass, cmDefaultDeviceID, cmDefaultProfileID, &previousProfileLocation); > if (error) { >- failedGettingCurrentProfile(error); >+ fprintf(stderr, "Failed to retrieve current color profile for main display, thus it won't be changed. Many pixel tests may fail as a result. (Error: %i)", error); >+ sInitialProfileLocation.locType = cmNoProfileBase; > return; > } >+ >+ CMProfileLocation location; >+ location.locType = cmFileBasedProfile; >+ NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:PROFILE_PATH]]; >+ FSRef fsRef; >+ if (url && CFURLGetFSRef((CFURLRef)url, &fsRef)) { >+ error = FSGetCatalogInfo(&fsRef, 0, 0, 0, &location.u.fileLoc.spec, 0); >+ if (error == noErr) >+ error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &location); >+ } >+ else >+ error = -1; > >- CMProfileRef previousProfile; >- error = CMOpenProfile(&previousProfile, &previousProfileLocation); > if (error) { >- failedGettingCurrentProfile(error); >+ fprintf(stderr, "Failed to set color profile for main display! Many pixel tests may fail as a result. (Error: %i)", error); >+ sInitialProfileLocation.locType = cmNoProfileBase; > return; > } >- >- CFStringRef previousProfileName; >- CFStringRef genericProfileName; >- char previousProfileNameString[1024]; >- char genericProfileNameString[1024]; >- CMCopyProfileDescriptionString(previousProfile, &previousProfileName); >- CMCopyProfileDescriptionString(genericProfile, &genericProfileName); >- CFStringGetCString(previousProfileName, previousProfileNameString, sizeof(previousProfileNameString), kCFStringEncodingUTF8); >- CFStringGetCString(genericProfileName, genericProfileNameString, sizeof(previousProfileNameString), kCFStringEncodingUTF8); >- CFRelease(previousProfileName); >- CFRelease(genericProfileName); >- >- CMCloseProfile(previousProfile); >- >- fprintf(stderr, "\n\nWARNING: Temporarily changing your system color profile from \"%s\" to \"%s\".\n", previousProfileNameString, genericProfileNameString); >+ >+ // Other signals are handled in installSignalHandlers() which also calls restoreMainDisplayColorProfile() >+ signal(SIGINT, restoreMainDisplayColorProfile); >+ signal(SIGHUP, restoreMainDisplayColorProfile); >+ signal(SIGTERM, restoreMainDisplayColorProfile); >+ >+ fprintf(stderr, "\n\nWARNING: Temporarily changing the main display color profile to \"%s\": the colors on your screen will change for the duration of the testing.\n", PROFILE_PATH); > fprintf(stderr, "This allows the WebKit pixel-based regression tests to have consistent color values across all machines.\n"); >- fprintf(stderr, "The colors on your screen will change for the duration of the testing.\n\n"); >- >- CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; >- if ((error = CMSetDeviceProfile(cmDisplayDeviceClass, cmDefaultDeviceID, &scope, cmDefaultProfileID, &genericProfileLocation))) { >- fprintf(stderr, "Failed to set color profile to \"%s\"! Many pixel tests will fail as a result. (Error: %i)", >- genericProfileNameString, error); >- } else { >- currentColorProfileLocation = previousProfileLocation; >- changedColorProfile = true; >- signal(SIGINT, restoreColorSpace); >- signal(SIGHUP, restoreColorSpace); >- signal(SIGTERM, restoreColorSpace); >- } > } > >-void initializeColorSpaceAndScreeBufferForPixelTests() >-{ >- setDefaultColorProfileToRGB(); >- screenCaptureBuffer = (unsigned char *)malloc(maxViewHeight * maxViewWidth * 4); >- sharedColorSpace = CGColorSpaceCreateDeviceRGB(); >-} >- >-// Declared in PixelDumpSupportCG.h >- >-RetainPtr<CGContextRef> getBitmapContextFromWebView() >+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect) > { >- NSSize webViewSize = [[mainFrame webView] frame].size; >- return RetainPtr<CGContextRef>(AdoptCF, CGBitmapContextCreate(screenCaptureBuffer, static_cast<size_t>(webViewSize.width), static_cast<size_t>(webViewSize.height), 8, static_cast<size_t>(webViewSize.width) * 4, sharedColorSpace, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast)); >-} >- >-void paintWebView(CGContextRef context) >-{ >- RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; >- >- NSGraphicsContext* nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; >- [NSGraphicsContext setCurrentContext:nsContext]; >- > WebView* view = [mainFrame webView]; >- [view displayIfNeeded]; >- [view lockFocus]; >- NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:[view frame]]; >- [view unlockFocus]; >- [imageRep draw]; >- [imageRep release]; >- >- [NSGraphicsContext setCurrentContext:savedContext.get()]; >-} >- >-void repaintWebView(CGContextRef context, bool horizontal) >-{ >- RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; >- >- NSGraphicsContext* nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; >- [NSGraphicsContext setCurrentContext:nsContext]; >- >- WebView *view = [mainFrame webView]; > NSSize webViewSize = [view frame].size; >+ size_t pixelsWide = static_cast<size_t>(webViewSize.width); >+ size_t pixelsHigh = static_cast<size_t>(webViewSize.height); >+ size_t rowBytes = (4 * pixelsWide + 63) & ~63; // Use a multiple of 64 bytes to improve CG performance >+ >+ void *buffer = calloc(pixelsHigh, rowBytes); >+ if (!buffer) >+ return 0; >+ >+ static CGColorSpaceRef colorSpace = 0; >+ if (!colorSpace) { >+ CMProfileLocation location; >+ location.locType = cmFileBasedProfile; >+ NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:PROFILE_PATH]]; >+ FSRef fsRef; >+ if (url && CFURLGetFSRef((CFURLRef)url, &fsRef)) { >+ if (FSGetCatalogInfo(&fsRef, 0, 0, 0, &location.u.fileLoc.spec, 0) == noErr) { >+ CMProfileRef profile; >+ if (CMOpenProfile(&profile, &location) == noErr) { >+ colorSpace = CGColorSpaceCreateWithPlatformColorSpace(profile); >+ CMCloseProfile(profile); >+ } >+ } >+ } >+ } >+ >+ CGContextRef context = CGBitmapContextCreate(buffer, pixelsWide, pixelsHigh, 8, rowBytes, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); // Use ARGB8 on PPC or BGRA8 on X86 to improve CG performance >+ if (!context) { >+ free(buffer); >+ return 0; >+ } > >- if (horizontal) { >- for (NSRect column = NSMakeRect(0, 0, 1, webViewSize.height); column.origin.x < webViewSize.width; column.origin.x++) >- [view displayRectIgnoringOpacity:column inContext:nsContext]; >+ // The BitmapContext keeps the CGContextRef and the pixel buffer alive >+ RefPtr<BitmapContext> bitmapContext = BitmapContext::createByAdoptingBitmapAndContext(buffer, context); >+ >+ NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; >+ ASSERT(nsContext); >+ >+ if (incrementalRepaint) { >+ if (sweepHorizontally) { >+ for (NSRect column = NSMakeRect(0, 0, 1, webViewSize.height); column.origin.x < webViewSize.width; column.origin.x++) >+ [view displayRectIgnoringOpacity:column inContext:nsContext]; >+ } else { >+ for (NSRect line = NSMakeRect(0, 0, webViewSize.width, 1); line.origin.y < webViewSize.height; line.origin.y++) >+ [view displayRectIgnoringOpacity:line inContext:nsContext]; >+ } > } else { >- for (NSRect line = NSMakeRect(0, 0, webViewSize.width, 1); line.origin.y < webViewSize.height; line.origin.y++) >- [view displayRectIgnoringOpacity:line inContext:nsContext]; >+ if (onscreen) { >+#ifdef BUILDING_ON_LEOPARD >+ // Ask the window server to provide us a composited version of the *real* window content including surfaces (i.e. OpenGL content) >+ // Note that the returned image might differ very slightly from the window backing because of dithering artifacts in the window server compositor >+ >+ CGImageRef image = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [[view window] windowNumber], kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque); >+ CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); >+ CGImageRelease(image); >+#else >+ // On 10.4 and earlier, we have to move the window temporarily "onscreen" and read directly from the display framebuffer using OpenGL >+ // In this code path, we need to ensure the window is above any other window or captured result will be corrupted >+ >+ NSWindow *window = [view window]; >+ int oldLevel = [window level]; >+ NSRect oldFrame = [window frame]; >+ >+ NSRect newFrame = [[[NSScreen screens] objectAtIndex:0] frame]; >+ newFrame = NSMakeRect(newFrame.origin.x + (newFrame.size.width - oldFrame.size.width) / 2, newFrame.origin.y + (newFrame.size.height - oldFrame.size.height) / 2, oldFrame.size.width, oldFrame.size.height); >+ [window setLevel:NSScreenSaverWindowLevel]; >+ [window setFrame:newFrame display:NO animate:NO]; >+ >+ CGRect rect = CGRectMake(newFrame.origin.x, newFrame.origin.y, webViewSize.width, webViewSize.height); >+ CGDirectDisplayID displayID; >+ CGDisplayCount count; >+ if (CGGetDisplaysWithRect(rect, 1, &displayID, &count) == kCGErrorSuccess) { >+ CGRect bounds = CGDisplayBounds(displayID); >+ rect.origin.x -= bounds.origin.x; >+ rect.origin.y -= bounds.origin.y; >+ >+ CGLPixelFormatAttribute attributes[] = {kCGLPFAAccelerated, kCGLPFANoRecovery, kCGLPFAFullScreen, kCGLPFADisplayMask, (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(displayID), (CGLPixelFormatAttribute)0}; >+ CGLPixelFormatObj pixelFormat; >+ GLint num; >+ if (CGLChoosePixelFormat(attributes, &pixelFormat, &num) == kCGLNoError) { >+ CGLContextObj cgl_ctx; >+ if (CGLCreateContext(pixelFormat, 0, &cgl_ctx) == kCGLNoError) { >+ if (CGLSetFullScreen(cgl_ctx) == kCGLNoError) { >+ void *flipBuffer = calloc(pixelsHigh, rowBytes); >+ if (flipBuffer) { >+ glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4); >+ glPixelStorei(GL_PACK_ALIGNMENT, 4); >+#if __BIG_ENDIAN__ >+ glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, flipBuffer); >+#else >+ glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, flipBuffer); >+#endif >+ if (!glGetError()) { >+ for(size_t i = 0; i < pixelsHigh; ++i) >+ bcopy((char*)flipBuffer + rowBytes * i, (char*)buffer + rowBytes * (pixelsHigh - i - 1), pixelsWide * 4); >+ } >+ >+ free(flipBuffer); >+ } >+ } >+ CGLDestroyContext(cgl_ctx); >+ } >+ CGLDestroyPixelFormat(pixelFormat); >+ } >+ } >+ >+ [window setFrame:oldFrame display:NO animate:NO]; >+ [window setLevel:oldLevel]; >+#endif >+ } else { >+ // Grab directly the contents of the window backing buffer (this ignores any surfaces on the window) >+ // FIXME: This path is suboptimal: data is read from window backing store, converted to RGB8 then drawn again into an RGBA8 bitmap >+ >+ [view displayIfNeeded]; >+ [view lockFocus]; >+ NSBitmapImageRep *imageRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:[view frame]] autorelease]; >+ [view unlockFocus]; >+ >+ RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; >+ [NSGraphicsContext setCurrentContext:nsContext]; >+ [imageRep draw]; >+ [NSGraphicsContext setCurrentContext:savedContext.get()]; >+ } > } > >- [NSGraphicsContext setCurrentContext:savedContext.get()]; >-} >- >-CGRect getSelectionRect() >-{ >- NSView *documentView = [[mainFrame frameView] documentView]; >- if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) { >+ if (drawSelectionRect) { >+ NSView *documentView = [[mainFrame frameView] documentView]; >+ ASSERT([documentView conformsToProtocol:@protocol(WebDocumentSelection)]); > NSRect rect = [documentView convertRect:[(id <WebDocumentSelection>)documentView selectionRect] fromView:nil]; >- return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); >+ CGContextSaveGState(context); >+ CGContextSetLineWidth(context, 1.0); >+ CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0); >+ CGContextStrokeRect(context, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); >+ CGContextRestoreGState(context); > } >- >- ASSERT_NOT_REACHED(); >- return CGRectZero; >+ >+ return bitmapContext.release(); > } >diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp >index 1ce31de..742bd7f 100644 >--- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp >+++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp >@@ -38,25 +38,26 @@ > #include "UIDelegate.h" > #include "WorkQueueItem.h" > #include "WorkQueue.h" >+ >+#include <fcntl.h> >+#include <io.h> >+#include <math.h> >+#include <pthread.h> >+#include <shlwapi.h> >+#include <stdio.h> >+#include <string.h> >+#include <tchar.h> > #include <wtf/RetainPtr.h> > #include <wtf/Vector.h> >-#include <WebCore/COMPtr.h> >-#include <CoreFoundation/CoreFoundation.h> >+#include <windows.h> > #include <CFNetwork/CFURLCachePriv.h> >+#include <CoreFoundation/CoreFoundation.h> > #include <JavaScriptCore/JavaScriptCore.h> >-#include <math.h> >-#include <pthread.h> >-#include <string> >-#include <tchar.h> >+#include <WebCore/COMPtr.h> > #include <WebKit/ForEachCoClass.h> > #include <WebKit/WebKit.h> >-#include <fcntl.h> >-#include <io.h> >-#include <windows.h> >-#include <stdio.h> >-#include <shlwapi.h> > >-using std::wstring; >+using namespace std; > > #ifndef NDEBUG > const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug"; >@@ -78,8 +79,6 @@ static bool threaded = false; > static bool forceComplexText = false; > static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; > >-static const char* currentTest; >- > volatile bool done; > // This is the topmost frame that is loading, during a given load, or nil when no load is > // in progress. Usually this is the same as the main frame, but not always. In the case >@@ -562,7 +561,7 @@ void dump() > wstring result = dumpFramesAsText(frame); > resultString = SysAllocStringLen(result.data(), result.size()); > } else { >- bool isSVGW3CTest = strstr(currentTest, "svg\\W3C-SVG-1.1"); >+ bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg\\W3C-SVG-1.1") != string::npos); > unsigned width; > unsigned height; > if (isSVGW3CTest) { >@@ -608,7 +607,7 @@ void dump() > > if (dumpPixels) { > if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) >- dumpWebViewAsPixelsAndCompareWithExpected(currentTest, dumpAllPixels); >+ dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); > } > > printf("#EOF\n"); // terminate the (possibly empty) pixels block >@@ -675,13 +674,23 @@ static void resetWebViewToConsistentStateBeforeTesting() > webViewPrivate->clearMainFrameName(); > } > >-static void runTest(const char* pathOrURL) >+static void runTest(const string& testPathOrURL) > { > static BSTR methodBStr = SysAllocString(TEXT("GET")); > >+ // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. >+ string pathOrURL(testPathOrURL); >+ string expectedPixelHash; >+ >+ size_t separatorPos = pathOrURL.find("'"); >+ if (separatorPos != string::npos) { >+ pathOrURL = string(testPathOrURL, 0, separatorPos); >+ expectedPixelHash = string(testPathOrURL, separatorPos + 1); >+ } >+ > BSTR urlBStr; > >- CFStringRef str = CFStringCreateWithCString(0, pathOrURL, kCFStringEncodingWindowsLatin1); >+ CFStringRef str = CFStringCreateWithCString(0, pathOrURL.c_str(), kCFStringEncodingWindowsLatin1); > CFURLRef url = CFURLCreateWithString(0, str, 0); > > if (!url) >@@ -700,13 +709,11 @@ static void runTest(const char* pathOrURL) > > CFRelease(url); > >- currentTest = pathOrURL; >- >- ::gLayoutTestController = new LayoutTestController(false, false); >+ ::gLayoutTestController = new LayoutTestController(pathOrURL, expectedPixelHash); > done = false; > topLoadingFrame = 0; > >- if (shouldLogFrameLoadDelegates(pathOrURL)) >+ if (shouldLogFrameLoadDelegates(pathOrURL.c_str())) > gLayoutTestController->setDumpFrameLoadCallbacks(true); > > COMPtr<IWebHistory> history(Create, CLSID_WebHistory); >diff --git a/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp b/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp >index 2f23158..d0b79e1 100644 >--- a/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp >+++ b/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp >@@ -34,7 +34,7 @@ > #include <wtf/Assertions.h> > #include <wtf/RetainPtr.h> > >-RetainPtr<CGContextRef> getBitmapContextFromWebView() >+PassRefPtr<BitmapContext> getBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect) > { > RECT frame; > if (!GetWindowRect(webViewWindow, &frame)) >@@ -48,8 +48,6 @@ RetainPtr<CGContextRef> getBitmapContextFromWebView() > bmp.bmiHeader.biBitCount = 32; > bmp.bmiHeader.biCompression = BI_RGB; > >- // FIXME: Currently we leak this HBITMAP because we don't have a good way >- // to destroy it when the CGBitmapContext gets destroyed. > void* bits = 0; > HBITMAP bitmap = CreateDIBSection(0, &bmp, DIB_RGB_COLORS, &bits, 0, 0); > >@@ -63,6 +61,8 @@ RetainPtr<CGContextRef> getBitmapContextFromWebView() > ASSERT(info.bmBitsPixel == 32); > > RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); >- return RetainPtr<CGContextRef>(AdoptCF, CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, >- info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst)); >+ CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, >+ info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); >+ >+ return BitmapContext::createByAdoptingBitmapAndContext(bitmap, context); > } >diff --git a/WebKitTools/Scripts/run-webkit-tests b/WebKitTools/Scripts/run-webkit-tests >index 2bb1096..c012724 100755 >--- a/WebKitTools/Scripts/run-webkit-tests >+++ b/WebKitTools/Scripts/run-webkit-tests >@@ -112,8 +112,6 @@ my $launchSafari = 1; > my $platform; > my $pixelTests = ''; > my $quiet = ''; >-my $repaintSweepHorizontally = ''; >-my $repaintTests = ''; > my $report10Slowest = 0; > my $resetResults = 0; > my $shouldCheckLeaks = 0; >@@ -123,7 +121,7 @@ my $testHTTP = 1; > my $testMedia = 1; > my $testResultsDirectory = "/tmp/layout-test-results"; > my $threaded = 0; >-my $threshold = 0; >+my $tolerance = 0; > my $treatSkipped = "default"; > my $verbose = 0; > my $useValgrind = 0; >@@ -180,17 +178,16 @@ Usage: $programName [options] [testdir|testpath ...] > -c|--configuration config Set DumpRenderTree build configuration > -g|--guard-malloc Enable malloc guard > --help Show this help message >- -h|--horizontal-sweep Change repaint to sweep horizontally instead of vertically (implies --repaint-tests) > --[no-]http Run (or do not run) http tests (default: $httpDefault) > -i|--ignore-tests Comma-separated list of directories or tests to ignore > --[no-]launch-safari Launch (or do not launch) Safari to display test results (default: $launchSafariDefault) > -l|--leaks Enable leaks checking > --[no-]new-test-results Generate results for new tests > -p|--pixel-tests Enable pixel tests >+ --tolerance t Ignore image differences less than this percentage (implies --pixel-tests) > --platform Override the detected platform to use for tests and results (default: $platform) > --port Web server port to use with http tests > -q|--quiet Less verbose output >- -r|--repaint-tests Run repaint tests (implies --pixel-tests) > --reset-results Reset ALL results (including pixel tests if --pixel-tests is set) > -o|--results-directory Output results directory (default: $testResultsDirectory) > --random Run the tests in a random order >@@ -206,7 +203,6 @@ Usage: $programName [options] [testdir|testpath ...] > --strict Do a comparison with the output on Mac (Qt only) > --[no-]strip-editing-callbacks Remove editing callbacks from expected results > -t|--threaded Run a concurrent JavaScript thead with each test >- --threshold t Ignore pixel value deviations less than or equal to t > --valgrind Run DumpRenderTree inside valgrind (Qt/Linux only) > -v|--verbose More verbose output (overrides --quiet) > -m|--merge-leak-depth arg Merges leak callStacks and prints the number of unique leaks beneath a callstack depth of arg. Defaults to 5. >@@ -221,7 +217,6 @@ my $getOptionsResult = GetOptions( > 'c|configuration=s' => \$configuration, > 'guard-malloc|g' => \$guardMalloc, > 'help' => \$showHelp, >- 'horizontal-sweep|h' => \$repaintSweepHorizontally, > 'http!' => \$testHTTP, > 'ignore-tests|i=s' => \$ignoreTests, > 'launch-safari!' => \$launchSafari, >@@ -230,7 +225,6 @@ my $getOptionsResult = GetOptions( > 'platform=s' => \$platform, > 'port=i' => \$httpdPort, > 'quiet|q' => \$quiet, >- 'repaint-tests|r' => \$repaintTests, > 'reset-results' => \$resetResults, > 'new-test-results!' => \$generateNewResults, > 'results-directory|o=s' => \$testResultsDirectory, >@@ -239,7 +233,7 @@ my $getOptionsResult = GetOptions( > 'skipped=s' => \&validateSkippedArg, > 'slowest' => \$report10Slowest, > 'threaded|t' => \$threaded, >- 'threshold=i' => \$threshold, >+ 'tolerance=f' => \$tolerance, > 'verbose|v' => \$verbose, > 'valgrind' => \$useValgrind, > 'sample-on-timeout!' => \$runSample, >@@ -267,10 +261,7 @@ setConfiguration($configuration); > > my $configurationOption = "--" . lc($configuration); > >-$repaintTests = 1 if $repaintSweepHorizontally; >- >-$pixelTests = 1 if $repaintTests; >-$pixelTests = 1 if $threshold > 0; >+$pixelTests = 1 if $tolerance > 0; > > $testsPerDumpTool = 1000 if !$testsPerDumpTool; > >@@ -291,7 +282,7 @@ setRun64Bit($run64Bit); > > chdirWebKit(); > >-if(!defined($root)){ >+if (!defined($root)) { > # Push the parameters to build-dumprendertree as an array > my @args; > push(@args, $configurationOption); >@@ -454,19 +445,15 @@ my %durations; > my $count = 0; > my $leaksOutputFileNumber = 1; > my $totalLeaks = 0; >-my $dumpAllPixels = $pixelTests && $resetResults; > > my @toolArgs = (); >-push @toolArgs, "--dump-all-pixels" if $dumpAllPixels; > push @toolArgs, "--pixel-tests" if $pixelTests; >-push @toolArgs, "--repaint" if $repaintTests; >-push @toolArgs, "--horizontal-sweep" if $repaintSweepHorizontally; > push @toolArgs, "--threaded" if $threaded; > push @toolArgs, "--complex-text" if $complexText; > push @toolArgs, "-"; > > my @diffToolArgs = (); >-push @diffToolArgs, "--threshold", $threshold; >+push @diffToolArgs, "--tolerance", $tolerance; > > $| = 1; > >@@ -553,6 +540,20 @@ for my $test (@tests) { > > my $startTime = time if $report10Slowest; > >+ # Try to read expected hash file for pixel tests >+ my $suffixExpectedHash = ""; >+ if ($pixelTests && !$resetResults) { >+ my $expectedPixelDir = expectedDirectoryForTest($base, 0, "png"); >+ if (open EXPECTEDHASH, "$expectedPixelDir/$base-$expectedTag.checksum") { >+ my $expectedHash = <EXPECTEDHASH>; >+ chomp($expectedHash); >+ close EXPECTEDHASH; >+ >+ # Format expected hash into a suffix string that is appended to the path / URL passed to DRT >+ $suffixExpectedHash = "'$expectedHash"; >+ } >+ } >+ > if ($test !~ /^http\//) { > my $testPath = "$testDirectory/$test"; > if (isCygwin()) { >@@ -560,17 +561,17 @@ for my $test (@tests) { > } else { > $testPath = canonpath($testPath); > } >- print OUT "$testPath\n"; >+ print OUT "$testPath$suffixExpectedHash\n"; > } else { > openHTTPDIfNeeded(); > if ($test !~ /^http\/tests\/local\// && $test !~ /^http\/tests\/ssl\// && $test !~ /^http\/tests\/media\//) { > my $path = canonpath($test); > $path =~ s/^http\/tests\///; >- print OUT "http://127.0.0.1:$httpdPort/$path\n"; >+ print OUT "http://127.0.0.1:$httpdPort/$path$suffixExpectedHash\n"; > } elsif ($test =~ /^http\/tests\/ssl\//) { > my $path = canonpath($test); > $path =~ s/^http\/tests\///; >- print OUT "https://127.0.0.1:$httpdSSLPort/$path\n"; >+ print OUT "https://127.0.0.1:$httpdSSLPort/$path$suffixExpectedHash\n"; > } else { > my $testPath = "$testDirectory/$test"; > if (isCygwin()) { >@@ -578,7 +579,7 @@ for my $test (@tests) { > } else { > $testPath = canonpath($testPath); > } >- print OUT "$testPath\n"; >+ print OUT "$testPath$suffixExpectedHash\n"; > } > } > >@@ -641,7 +642,6 @@ for my $test (@tests) { > my $diffPercentage = ""; > my $diffResult = "passed"; > >- # Look for the pixel block, and do an image diff if we find one > my $actualHash = ""; > my $expectedHash = ""; > my $actualPNGSize = 0; >@@ -650,7 +650,7 @@ for my $test (@tests) { > last if /#EOF/; > if (/ActualHash: ([a-f0-9]{32})/) { > $actualHash = $1; >- } elsif (/BaselineHash: ([a-f0-9]{32})/) { >+ } elsif (/ExpectedHash: ([a-f0-9]{32})/) { > $expectedHash = $1; > } elsif (/Content-Length: (\d+)\s*/) { > $actualPNGSize = $1; >@@ -658,42 +658,58 @@ for my $test (@tests) { > } > } > >- # If we got some PNG data, diff with expected >+ if ($verbose && $pixelTests && !$resetResults && $actualPNGSize) { >+ if ($actualHash eq "" && $expectedHash eq "") { >+ printFailureMessageForTest($test, "WARNING: actual & expected pixel hashes are missing!"); >+ } elsif ($actualHash eq "") { >+ printFailureMessageForTest($test, "WARNING: actual pixel hash is missing!"); >+ } elsif ($expectedHash eq "") { >+ printFailureMessageForTest($test, "WARNING: expected pixel hash is missing!"); >+ } >+ } >+ > if ($actualPNGSize > 0) { > my $expectedPixelDir = expectedDirectoryForTest($base, $isText, "png"); > >- if ($expectedHash ne $actualHash && -f "$expectedPixelDir/$base-$expectedTag.png") { >- my $expectedPNGSize = -s "$expectedPixelDir/$base-$expectedTag.png"; >- my $expectedPNG = ""; >- open EXPECTEDPNG, "$expectedPixelDir/$base-$expectedTag.png"; >- read(EXPECTEDPNG, $expectedPNG, $expectedPNGSize); >+ if (!$resetResults && ($expectedHash ne $actualHash || ($actualHash eq "" && $expectedHash eq ""))) { >+ if (-f "$expectedPixelDir/$base-$expectedTag.png") { >+ my $expectedPNGSize = -s "$expectedPixelDir/$base-$expectedTag.png"; >+ my $expectedPNG = ""; >+ open EXPECTEDPNG, "$expectedPixelDir/$base-$expectedTag.png"; >+ read(EXPECTEDPNG, $expectedPNG, $expectedPNGSize); > >- print DIFFOUT "Content-Length: $actualPNGSize\n"; >- print DIFFOUT $actualPNG; >+ print DIFFOUT "Content-Length: $actualPNGSize\n"; >+ print DIFFOUT $actualPNG; > >- print DIFFOUT "Content-Length: $expectedPNGSize\n"; >- print DIFFOUT $expectedPNG; >+ print DIFFOUT "Content-Length: $expectedPNGSize\n"; >+ print DIFFOUT $expectedPNG; > >- while (<DIFFIN>) { >- last if /^error/ || /^diff:/; >- if (/Content-Length: (\d+)\s*/) { >- read(DIFFIN, $diffPNG, $1); >+ while (<DIFFIN>) { >+ last if /^error/ || /^diff:/; >+ if (/Content-Length: (\d+)\s*/) { >+ read(DIFFIN, $diffPNG, $1); >+ } > } >- } > >- if (/^diff: (.+)% (passed|failed)/) { >- $diffPercentage = $1; >- $imageDifferences{$base} = $diffPercentage; >- $diffResult = $2; >+ if (/^diff: (.+)% (passed|failed)/) { >+ $diffPercentage = $1; >+ $imageDifferences{$base} = $diffPercentage; >+ $diffResult = $2; >+ } >+ >+ if ($diffPercentage == 0) { >+ printFailureMessageForTest($test, "pixel hash failed (but pixel test still passes)"); >+ } >+ } elsif ($verbose) { >+ printFailureMessageForTest($test, "WARNING: expected image is missing!"); > } > } > >- if ($actualPNGSize && ($resetResults || !-f "$expectedPixelDir/$base-$expectedTag.png")) { >+ if ($resetResults || !-f "$expectedPixelDir/$base-$expectedTag.png") { > mkpath catfile($expectedPixelDir, dirname($base)) if $testDirectory ne $expectedPixelDir; > writeToFile("$expectedPixelDir/$base-$expectedTag.png", $actualPNG); > } > >- # update the expected hash if the image diff said that there was no difference > if ($actualHash ne "" && ($resetResults || !-f "$expectedPixelDir/$base-$expectedTag.checksum")) { > writeToFile("$expectedPixelDir/$base-$expectedTag.checksum", $actualHash); > } >@@ -741,7 +757,7 @@ for my $test (@tests) { > system "diff -u \"/tmp/expected.txt\" \"/tmp/actual.txt\" > \"/tmp/simplified.diff\""; > > $diffResult = "failed"; >- if($verbose) { >+ if ($verbose) { > print "\n"; > system "cat /tmp/simplified.diff"; > print "failed!!!!!";
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
Flags:
mitz:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 21322
:
24037
|
24166
|
24196
|
24588
|
24631
|
24689
|
24702