Unreviewed, rolling out r216260.
authorjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 May 2017 20:52:37 +0000 (20:52 +0000)
committerjbedard@apple.com <jbedard@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 May 2017 20:52:37 +0000 (20:52 +0000)
Breaks internal iOS testers

Reverted changeset:

"Use ImageDiff built by host SDK and remove ImageDiff from
DumpRenderTree"
https://bugs.webkit.org/show_bug.cgi?id=168945
http://trac.webkit.org/changeset/216260

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@216271 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
Tools/DumpRenderTree/PlatformWin.cmake
Tools/DumpRenderTree/cg/ImageDiffCG.cpp [new file with mode: 0644]
Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig [new file with mode: 0644]
Tools/Scripts/webkitpy/port/darwin.py
Tools/Scripts/webkitpy/port/image_diff.py
Tools/Scripts/webkitpy/port/ios_simulator.py

index cab2989..4eb77c4 100644 (file)
@@ -1,5 +1,18 @@
 2017-05-05  Jonathan Bedard  <jbedard@apple.com>
 
+        Unreviewed, rolling out r216260.
+
+        Breaks internal iOS testers
+
+        Reverted changeset:
+
+        "Use ImageDiff built by host SDK and remove ImageDiff from
+        DumpRenderTree"
+        https://bugs.webkit.org/show_bug.cgi?id=168945
+        http://trac.webkit.org/changeset/216260
+
+2017-05-05  Jonathan Bedard  <jbedard@apple.com>
+
         Use ImageDiff built by host SDK and remove ImageDiff from DumpRenderTree
         https://bugs.webkit.org/show_bug.cgi?id=168945
         <rdar://problem/30745695>
index cf5c511..a59c86c 100644 (file)
@@ -27,6 +27,7 @@
                                CEB754D41BBDA26D009F0401 /* PBXTargetDependency */,
                                2D403F211508736C005358D2 /* PBXTargetDependency */,
                                A134E52D188FC09200901D06 /* PBXTargetDependency */,
+                               A84F608F08B1370E00E9745F /* PBXTargetDependency */,
                                141BF238096A451E00E0753C /* PBXTargetDependency */,
                        );
                        name = All;
@@ -79,7 +80,7 @@
                2D403F1B15087209005358D2 /* LayoutTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D403EA215087142005358D2 /* LayoutTestHelper.m */; };
                2DA2E3A51E1BA54100A3BBD0 /* DumpRenderTreeSpellChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2DA2E3A41E1BA54100A3BBD0 /* DumpRenderTreeSpellChecker.mm */; };
                31117B3D15D9A56A00163BC8 /* MockWebNotificationProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = 31117B3B15D9A56A00163BC8 /* MockWebNotificationProvider.mm */; };
-               312943F91E71F2B4001EE2CC /* IOSLayoutTestCommunication.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3148A0551E6F90F400D3B316 /* IOSLayoutTestCommunication.cpp */; };
+               312943F91E71F2B4001EE2CC /* IOOSLayoutTestCommunication.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3148A0551E6F90F400D3B316 /* IOSLayoutTestCommunication.cpp */; };
                4464CABE1C20A08B00E5BB55 /* DumpRenderTreeAppMain.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4464CABD1C20A07000E5BB55 /* DumpRenderTreeAppMain.mm */; };
                4AD6A11413C8124000EA9737 /* FormValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AD6A11313C8124000EA9737 /* FormValue.cpp */; };
                5106803E15CC7B10001A8A23 /* SlowNPPNew.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5106803D15CC7B10001A8A23 /* SlowNPPNew.cpp */; };
                BCA18C470C9B5B9400114369 /* DumpRenderTree.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCA18C460C9B5B9400114369 /* DumpRenderTree.mm */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations"; }; };
                BCB284CD0CFA83C8007E533E /* PixelDumpSupportCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */; };
                BCB284D60CFA83D1007E533E /* PixelDumpSupportMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCB2848C0CFA8221007E533E /* PixelDumpSupportMac.mm */; };
+               BCB284F60CFA84F8007E533E /* ImageDiffCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */; };
                BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */; };
                BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */; };
                BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF6C64F0C98E9C000AC063E /* GCController.cpp */; };
                        remoteGlobalIDString = A1321C9D188F9A3600125434;
                        remoteInfo = "DumpRenderTree (Library)";
                };
+               A84F608E08B1370E00E9745F /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = B5A7525A08AF4A4A00138E45;
+                       remoteInfo = ImageDiff;
+               };
                CEB754D31BBDA26D009F0401 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                AA5A15EE16E15CD000F7C561 /* AccessibilityUIElementIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityUIElementIOS.mm; path = ios/AccessibilityUIElementIOS.mm; sourceTree = "<group>"; };
                AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = "AHEM____.TTF"; path = "fonts/AHEM____.TTF"; sourceTree = "<group>"; };
                AE8257EF08D22389000507AB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+               B5A7526708AF4A4A00138E45 /* ImageDiff */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ImageDiff; sourceTree = BUILT_PRODUCTS_DIR; };
                B5A752A108AF5D1F00138E45 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
                BC0131D80C9772010087317D /* TestRunner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TestRunner.cpp; sourceTree = "<group>"; };
                BC0131D90C9772010087317D /* TestRunner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TestRunner.h; sourceTree = "<group>"; };
                BCB281EE0CFA713D007E533E /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = mac/Configurations/Base.xcconfig; sourceTree = "<group>"; };
                BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = DumpRenderTree.xcconfig; path = mac/Configurations/DumpRenderTree.xcconfig; sourceTree = "<group>"; };
                BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = DebugRelease.xcconfig; path = mac/Configurations/DebugRelease.xcconfig; sourceTree = "<group>"; };
+               BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = ImageDiff.xcconfig; path = mac/Configurations/ImageDiff.xcconfig; sourceTree = "<group>"; };
                BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xcconfig; name = TestNetscapePlugIn.xcconfig; path = mac/Configurations/TestNetscapePlugIn.xcconfig; sourceTree = "<group>"; };
                BCB284880CFA8202007E533E /* PixelDumpSupportCG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PixelDumpSupportCG.cpp; path = cg/PixelDumpSupportCG.cpp; sourceTree = "<group>"; };
                BCB284890CFA8202007E533E /* PixelDumpSupportCG.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PixelDumpSupportCG.h; path = cg/PixelDumpSupportCG.h; sourceTree = "<group>"; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               B5A7525F08AF4A4A00138E45 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
                        isa = PBXGroup;
                        children = (
                                9340995408540CAF007F3BC8 /* DumpRenderTree */,
+                               B5A7526708AF4A4A00138E45 /* ImageDiff */,
                                2D403F19150871F9005358D2 /* LayoutTestHelper */,
                                A1158D7F18927E7A0088C17B /* DumpRenderTree.app */,
                                A1321C9E188F9A3600125434 /* libDumpRenderTree.a */,
                                BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */,
                                A19317FD18928738001C52B1 /* DumpRenderTreeApp.xcconfig */,
                                A134E5391890671C00901D06 /* DumpRenderTreeLibrary.xcconfig */,
+                               BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */,
                                A1103B5B1892498F00738C87 /* LayoutTestHelper.xcconfig */,
                                BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */,
                        );
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               B5A7525B08AF4A4A00138E45 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
 /* End PBXHeadersBuildPhase section */
 
 /* Begin PBXNativeTarget section */
                        productReference = A1321C9E188F9A3600125434 /* libDumpRenderTree.a */;
                        productType = "com.apple.product-type.library.static";
                };
+               B5A7525A08AF4A4A00138E45 /* ImageDiff */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = B5A7526408AF4A4A00138E45 /* Build configuration list for PBXNativeTarget "ImageDiff" */;
+                       buildPhases = (
+                               B5A7525B08AF4A4A00138E45 /* Headers */,
+                               B5A7525D08AF4A4A00138E45 /* Sources */,
+                               B5A7525F08AF4A4A00138E45 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = ImageDiff;
+                       productInstallPath = "$(HOME)/bin";
+                       productName = DumpRenderTree;
+                       productReference = B5A7526708AF4A4A00138E45 /* ImageDiff */;
+                       productType = "com.apple.product-type.tool";
+               };
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
                                A1321C9D188F9A3600125434 /* DumpRenderTree (Library) */,
                                9340994A08540CAE007F3BC8 /* DumpRenderTree */,
                                A1158D7E18927E7A0088C17B /* DumpRenderTree.app */,
+                               B5A7525A08AF4A4A00138E45 /* ImageDiff */,
                                141BF21E096A441D00E0753C /* TestNetscapePlugIn */,
                                2D403EB2150871F9005358D2 /* LayoutTestHelper */,
                        );
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               B5A7525D08AF4A4A00138E45 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               BCB284F60CFA84F8007E533E /* ImageDiffCG.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
                        target = A1321C9D188F9A3600125434 /* DumpRenderTree (Library) */;
                        targetProxy = A193180118928C10001C52B1 /* PBXContainerItemProxy */;
                };
+               A84F608F08B1370E00E9745F /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = B5A7525A08AF4A4A00138E45 /* ImageDiff */;
+                       targetProxy = A84F608E08B1370E00E9745F /* PBXContainerItemProxy */;
+               };
                CEB754D41BBDA26D009F0401 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = A1158D7E18927E7A0088C17B /* DumpRenderTree.app */;
                        };
                        name = Production;
                };
+               90CBC3530F748B1300A712B7 /* Production */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */;
+                       buildSettings = {
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/$(WEBKIT_FRAMEWORK_RESOURCES_PATH)";
+                               SKIP_INSTALL = NO;
+                       };
+                       name = Production;
+               };
                90CBC3540F748B1300A712B7 /* Production */ = {
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */;
                        };
                        name = Release;
                };
+               B5A7526508AF4A4A00138E45 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */;
+                       buildSettings = {
+                       };
+                       name = Debug;
+               };
+               B5A7526608AF4A4A00138E45 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */;
+                       buildSettings = {
+                       };
+                       name = Release;
+               };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Production;
                };
+               B5A7526408AF4A4A00138E45 /* Build configuration list for PBXNativeTarget "ImageDiff" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               B5A7526508AF4A4A00138E45 /* Debug */,
+                               B5A7526608AF4A4A00138E45 /* Release */,
+                               90CBC3530F748B1300A712B7 /* Production */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Production;
+               };
 /* End XCConfigurationList section */
        };
        rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
index 9108ac4..75ea5ac 100644 (file)
@@ -58,6 +58,16 @@ list(APPEND TestNetscapePlugIn_LIBRARIES
     WebKit
 )
 
+set(ImageDiff_SOURCES
+    win/ImageDiffWin.cpp
+)
+
+set(ImageDiff_LIBRARIES
+   JavaScriptCore
+   WTF
+   WebKit
+)
+
 list(APPEND DumpRenderTree_INCLUDE_DIRECTORIES
     win
     TestNetscapePlugIn
@@ -90,6 +100,12 @@ if (${WTF_PLATFORM_WIN_CAIRO})
     list(APPEND DumpRenderTreeLib_SOURCES
         cairo/PixelDumpSupportCairo.cpp
     )
+    list(APPEND ImageDiff_SOURCES
+        win/ImageDiffCairo.cpp
+    )
+    list(APPEND ImageDiff_LIBRARIES
+        ${CAIRO_LIBRARIES}
+    )
 else ()
     list(APPEND DumpRenderTree_INCLUDE_DIRECTORIES
         cg
@@ -102,6 +118,14 @@ else ()
         CoreGraphics
         CoreText
     )
+    list(APPEND ImageDiff_SOURCES
+        cg/ImageDiffCG.cpp
+    )
+    list(APPEND ImageDiff_LIBRARIES
+       CoreFoundation
+       CoreGraphics
+       CoreText
+    )
 endif ()
 
 ADD_PRECOMPILED_HEADER("DumpRenderTreePrefix.h" "win/DumpRenderTreePrefix.cpp" DumpRenderTreeLib_SOURCES)
@@ -111,4 +135,13 @@ add_definitions(-DUSE_CONSOLE_ENTRY_POINT)
 add_library(DumpRenderTreeLib SHARED ${DumpRenderTreeLib_SOURCES})
 target_link_libraries(DumpRenderTreeLib ${DumpRenderTreeLib_LIBRARIES})
 
+add_executable(ImageDiff ${TOOLS_DIR}/win/DLLLauncher/DLLLauncherMain.cpp)
+target_link_libraries(ImageDiff shlwapi)
+set_target_properties(ImageDiff PROPERTIES OUTPUT_NAME "ImageDiff")
+
+add_library(ImageDiffLib SHARED ${ImageDiff_SOURCES})
+target_link_libraries(ImageDiffLib ${ImageDiff_LIBRARIES})
+
+add_dependencies(ImageDiff ImageDiffLib)
+
 add_definitions(-D_UNICODE)
diff --git a/Tools/DumpRenderTree/cg/ImageDiffCG.cpp b/Tools/DumpRenderTree/cg/ImageDiffCG.cpp
new file mode 100644 (file)
index 0000000..7dc05db
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2005, 2007, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>.  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 THE AUTHOR ``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 THE AUTHOR OR
+ * 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.
+ */
+
+// FIXME: We need to be able to include these defines from a config.h somewhere.
+#define JS_EXPORT_PRIVATE
+
+#include <stdio.h>
+#include <wtf/Platform.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(WIN)
+#include <winsock2.h>
+#include <windows.h>
+#include <fcntl.h>
+#include <io.h>
+#include <wtf/MathExtras.h>
+#endif
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <CoreGraphics/CGImage.h>
+#include <ImageIO/CGImageDestination.h>
+
+#if PLATFORM(IOS)
+#include <MobileCoreServices/UTCoreTypes.h>
+#elif PLATFORM(MAC)
+#include <LaunchServices/UTCoreTypes.h>
+#endif
+
+#ifndef CGFLOAT_DEFINED
+#ifdef __LP64__
+typedef double CGFloat;
+#else
+typedef float CGFloat;
+#endif
+#define CGFLOAT_DEFINED 1
+#endif
+
+using namespace std;
+
+#if PLATFORM(WIN)
+static const CFStringRef kUTTypePNG = CFSTR("public.png");
+#endif
+
+static RetainPtr<CGImageRef> createImageFromStdin(int bytesRemaining)
+{
+    unsigned char buffer[2048];
+    RetainPtr<CFMutableDataRef> data = adoptCF(CFDataCreateMutable(0, bytesRemaining));
+
+    while (bytesRemaining > 0) {
+        size_t bytesToRead = min(bytesRemaining, 2048);
+        size_t bytesRead = fread(buffer, 1, bytesToRead, stdin);
+        CFDataAppendBytes(data.get(), buffer, static_cast<CFIndex>(bytesRead));
+        bytesRemaining -= static_cast<int>(bytesRead);
+    }
+    RetainPtr<CGDataProviderRef> dataProvider = adoptCF(CGDataProviderCreateWithCFData(data.get()));
+    return adoptCF(CGImageCreateWithPNGDataProvider(dataProvider.get(), 0, false, kCGRenderingIntentDefault));
+}
+
+static void releaseMallocBuffer(void* info, const void* data, size_t size)
+{
+    free((void*)data);
+}
+
+static RetainPtr<CGImageRef> createDifferenceImage(CGImageRef baseImage, CGImageRef testImage, float& difference)
+{
+    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);
+    RetainPtr<CGContextRef> baseContext = adoptCF(CGBitmapContextCreate(baseBuffer, width, height, 8, rowBytes, CGImageGetColorSpace(baseImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+    CGContextDrawImage(baseContext.get(), CGRectMake(0, 0, width, height), baseImage);
+
+    // Draw test image in bitmap context
+    void* buffer = calloc(height, rowBytes);
+    RetainPtr<CGContextRef> context = adoptCF(CGBitmapContextCreate(buffer, width, height, 8, rowBytes, CGImageGetColorSpace(testImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+    CGContextDrawImage(context.get(), CGRectMake(0, 0, width, height), testImage);
+
+    // 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;
+        }
+    }
+    
+    // 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;
+
+    RetainPtr<CGImageRef> diffImage;
+    // 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;
+        }
+        
+        static CGColorSpaceRef diffColorspace = CGColorSpaceCreateDeviceGray();
+        RetainPtr<CGDataProviderRef> provider = adoptCF(CGDataProviderCreateWithData(0, diffBuffer, width * height, releaseMallocBuffer));
+        diffImage = adoptCF(CGImageCreate(width, height, 8, 8, width, diffColorspace, 0, provider.get(), 0, false, kCGRenderingIntentDefault));
+    }
+    else
+        free(diffBuffer);
+    
+    // Destroy drawing buffers
+    if (buffer)
+        free(buffer);
+    if (baseBuffer)
+        free(baseBuffer);
+    
+    return diffImage;
+}
+
+static inline bool imageHasAlpha(CGImageRef image)
+{
+    CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
+    
+    return (info >= kCGImageAlphaPremultipliedLast) && (info <= kCGImageAlphaFirst);
+}
+
+int main(int argc, const char* argv[])
+{
+#if PLATFORM(WIN)
+    _setmode(0, _O_BINARY);
+    _setmode(1, _O_BINARY);
+#endif
+
+    float tolerance = 0.0f;
+
+    for (int i = 1; i < argc; ++i) {
+        if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) {
+            if (i >= argc - 1)
+                exit(1);
+            tolerance = strtof(argv[i + 1], 0);
+            ++i;
+            continue;
+        }
+    }
+
+    char buffer[2048];
+    RetainPtr<CGImageRef> actualImage;
+    RetainPtr<CGImageRef> baselineImage;
+
+    while (fgets(buffer, sizeof(buffer), stdin)) {
+        // remove the CR
+        char* newLineCharacter = strchr(buffer, '\n');
+        if (newLineCharacter)
+            *newLineCharacter = '\0';
+
+        if (!strncmp("Content-Length: ", buffer, 16)) {
+            strtok(buffer, " ");
+            int imageSize = strtol(strtok(0, " "), 0, 10);
+
+            if (imageSize > 0 && !actualImage)
+                actualImage = createImageFromStdin(imageSize);
+            else if (imageSize > 0 && !baselineImage)
+                baselineImage = createImageFromStdin(imageSize);
+            else
+                fputs("Error: image size must be specified.\n", stderr);
+        }
+
+        if (actualImage && baselineImage) {
+            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 {
+                if (CGImageGetWidth(actualImage.get()) != CGImageGetWidth(baselineImage.get()) || CGImageGetHeight(actualImage.get()) != CGImageGetHeight(baselineImage.get())) {
+#if OS(WINDOWS)
+                    fprintf(stderr, "Error: test and reference images have different sizes. Test image is %Iux%Iu, reference image is %Iux%Iu\n",
+#else
+                    fprintf(stderr, "Error: test and reference images have different sizes. Test image is %zux%zu, reference image is %zux%zu\n",
+#endif
+                        CGImageGetWidth(actualImage.get()), CGImageGetHeight(actualImage.get()),
+                        CGImageGetWidth(baselineImage.get()), CGImageGetHeight(baselineImage.get()));
+                } else if (imageHasAlpha(actualImage.get()) != imageHasAlpha(baselineImage.get()))
+                    fprintf(stderr, "Error: test and reference images differ in alpha. Test image %s alpha, reference image %s alpha.\n",
+                        imageHasAlpha(actualImage.get()) ? "has" : "does not have",
+                        imageHasAlpha(baselineImage.get()) ? "has" : "does not have");
+            }
+            
+            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());
+#if OS(WINDOWS)
+                    printf("Content-Length: %Iu\n", static_cast<size_t>(CFDataGetLength(imageData.get())));
+#else
+                    printf("Content-Length: %zu\n", static_cast<size_t>(CFDataGetLength(imageData.get())));
+#endif
+                    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;
+        }
+
+        fflush(stdout);
+    }
+
+    return 0;
+}
diff --git a/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig b/Tools/DumpRenderTree/mac/Configurations/ImageDiff.xcconfig
new file mode 100644 (file)
index 0000000..def6d8a
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright (C) 2009 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. ``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
+// 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 "BaseTarget.xcconfig"
+
+PRODUCT_NAME = ImageDiff;
+OTHER_LDFLAGS[sdk=macosx*] = $(inherited) -framework Carbon -framework Cocoa -framework QuartzCore;
+OTHER_LDFLAGS[sdk=iphone*] = $(inherited) -framework CoreFoundation -framework CoreGraphics -framework MobileCoreServices -framework ImageIO;
index 0e0c370..5fe521b 100644 (file)
@@ -174,26 +174,6 @@ class DarwinPort(ApplePort):
                     sample_files[test_name] = spindump_file
         return sample_files
 
-    def _path_to_image_diff(self):
-        # ImageDiff for DarwinPorts is a little complicated. It will either be in
-        # a directory named ../mac relative to the port build directory, in a directory
-        # named ../<build-type> relative to the port build directory or in the port build directory
-        _image_diff_in_build_path = super(DarwinPort, self)._path_to_image_diff()
-        _port_build_dir = self.host.filesystem.dirname(_image_diff_in_build_path)
-
-        # Test ../mac
-        _path_to_test = self.host.filesystem.join(_port_build_dir, '..', 'mac', 'ImageDiff')
-        if self.host.filesystem.exists(_path_to_test):
-            return _path_to_test
-
-        # Test ../<build-type>
-        _build_type = self.host.filesystem.basename(_port_build_dir).split('-')[0]
-        _path_to_test = self.host.filesystem.join(_port_build_dir, '..', _build_type, 'ImageDiff')
-        if self.host.filesystem.exists(_path_to_test):
-            return _path_to_test
-
-        return _image_diff_in_build_path
-
     def make_command(self):
         return self.xcrun_find('make', '/usr/bin/make')
 
index 5004548..9f9acec 100644 (file)
@@ -115,3 +115,15 @@ class ImageDiffer(object):
         if self._process:
             self._process.stop()
             self._process = None
+
+
+class IOSSimulatorImageDiffer(ImageDiffer):
+    def _start(self, tolerance):
+        # FIXME: Using "booted" is not 100% correct, we should use a device ID that we created.
+        # FIXME: Is it a problem that ImageDiff and simctl remain separate processes? This code used to pass --adopt-pid to sim tool.
+        # We should probably just build and use a host version of ImageDiff instead of a simulator one to solve both.
+        command = ['xcrun', '-sdk', 'iphonesimulator', 'simctl', 'spawn', 'booted', self._port._path_to_image_diff(), '--tolerance', str(tolerance)]
+        environment = self._port.setup_environ_for_server('ImageDiff')
+        self._process = self._port._server_process_constructor(self._port, 'ImageDiff', command, environment)
+        self._process.start()
+        self._tolerance = tolerance
index 155281e..a1440c7 100644 (file)
@@ -29,6 +29,7 @@ import subprocess
 import time
 
 from webkitpy.common.memoized import memoized
+from webkitpy.port import image_diff
 from webkitpy.port.device import Device
 from webkitpy.port.ios import IOSPort
 from webkitpy.xcode.simulator import Simulator, Runtime, DeviceType
@@ -327,6 +328,18 @@ class IOSSimulatorPort(IOSPort):
     def get_simulator_path(self, suffix=""):
         return os.path.join(self.SIMULATOR_DIRECTORY, "Simulator" + str(suffix) + ".app")
 
+    def diff_image(self, expected_contents, actual_contents, tolerance=None):
+        if not actual_contents and not expected_contents:
+            return (None, 0, None)
+        if not actual_contents or not expected_contents:
+            return (True, 0, None)
+        if not self._image_differ:
+            self._image_differ = image_diff.IOSSimulatorImageDiffer(self)
+        self.set_option_default('tolerance', 0.1)
+        if tolerance is None:
+            tolerance = self.get_option('tolerance')
+        return self._image_differ.diff_image(expected_contents, actual_contents, tolerance)
+
     def reset_preferences(self):
         _log.debug("reset_preferences")
         self._quit_ios_simulator()