<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[37270] trunk/WebKitTools</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/37270">37270</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2008-10-03 17:21:23 -0700 (Fri, 03 Oct 2008)</dd>
</dl>

<h3>Log Message</h3>
<pre>2008-10-03  Pierre-Olivier Latour &lt;pol@apple.com&gt;

        Reviewed by Darin Adler

        Render images to RGBA8 bitmaps independently of platform endianness.

        Create image difference bitmap in reference image colorspace instead of device colorspace
        (which depends on the main display profile), so that no color matching happens.

        https://bugs.webkit.org/show_bug.cgi?id=21336

        * DumpRenderTree/cg/ImageDiffCG.cpp:
        (createDifferenceBitmap):
        (computePercentageDifferent):
        (compareImages):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebKitToolsChangeLog">trunk/WebKitTools/ChangeLog</a></li>
<li><a href="#trunkWebKitToolsDumpRenderTreecgImageDiffCGcpp">trunk/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebKitToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebKitTools/ChangeLog (37269 => 37270)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKitTools/ChangeLog        2008-10-04 00:16:58 UTC (rev 37269)
+++ trunk/WebKitTools/ChangeLog        2008-10-04 00:21:23 UTC (rev 37270)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2008-10-03  Pierre-Olivier Latour &lt;pol@apple.com&gt;
+
+        Reviewed by Darin Adler
+
+        Render images to RGBA8 bitmaps independently of platform endianness.
+
+        Create image difference bitmap in reference image colorspace instead of device colorspace
+        (which depends on the main display profile), so that no color matching happens.
+
+        https://bugs.webkit.org/show_bug.cgi?id=21336
+
+        * DumpRenderTree/cg/ImageDiffCG.cpp:
+        (createDifferenceBitmap):
+        (computePercentageDifferent):
+        (compareImages):
+
</ins><span class="cx"> 2008-10-02  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Darin Adler
</span></span></pre></div>
<a id="trunkWebKitToolsDumpRenderTreecgImageDiffCGcpp"></a>
<div class="modfile"><h4>Modified: trunk/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp (37269 => 37270)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp        2008-10-04 00:16:58 UTC (rev 37269)
+++ trunk/WebKitTools/DumpRenderTree/cg/ImageDiffCG.cpp        2008-10-04 00:21:23 UTC (rev 37270)
</span><span class="lines">@@ -72,33 +72,44 @@
</span><span class="cx">     return RetainPtr&lt;CGImageRef&gt;(AdoptCF, CGImageCreateWithPNGDataProvider(dataProvider.get(), 0, false, kCGRenderingIntentDefault));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static RetainPtr&lt;CGContextRef&gt; getDifferenceBitmap(CGImageRef testBitmap, CGImageRef referenceBitmap)
</del><ins>+// Generates an RGBA8 bitmap in the reference image colorspace containing the differences between the 2 images
+static RetainPtr&lt;CGContextRef&gt; createDifferenceBitmap(CGImageRef testImage, CGImageRef referenceImage)
</ins><span class="cx"> {
</span><span class="cx">     // we must have both images to take diff
</span><del>-    if (!testBitmap || !referenceBitmap)
</del><ins>+    if (!testImage || !referenceImage) {
+        fprintf(stderr, &quot;test or reference image is missing!&quot;);
</ins><span class="cx">         return 0;
</span><ins>+    }
</ins><span class="cx"> 
</span><del>-    RetainPtr&lt;CGColorSpaceRef&gt; colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
</del><ins>+    // we must have both images be the same dimensions
+    if ((CGImageGetWidth(testImage) != CGImageGetWidth(referenceImage)) || (CGImageGetHeight(testImage) != CGImageGetHeight(referenceImage))) {
+        fprintf(stderr, &quot;test and reference image dimensions don't match!&quot;);
+        return 0;
+    }
+
+    // we must have both images in the same colorspace
+    if (!CFEqual(CGImageGetColorSpace(testImage), CGImageGetColorSpace(referenceImage))) {
+        fprintf(stderr, &quot;test and reference image colorspaces don't match!&quot;);
+        return 0;
+    }
+
</ins><span class="cx">     static CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
</span><del>-    CFDataSetLength(data, CGImageGetHeight(testBitmap) * CGImageGetBytesPerRow(testBitmap));
-    RetainPtr&lt;CGContextRef&gt; context(AdoptCF, CGBitmapContextCreate(CFDataGetMutableBytePtr(data), CGImageGetWidth(testBitmap), CGImageGetHeight(testBitmap),
-        CGImageGetBitsPerComponent(testBitmap), CGImageGetBytesPerRow(testBitmap), colorSpace.get(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
</del><ins>+    size_t rowBytes = (4 * CGImageGetWidth(referenceImage) + 63) &amp; ~63; // Use a multiple of 64 bytes to improve CG performance
+    CFDataSetLength(data, CGImageGetHeight(referenceImage) * rowBytes);
+    RetainPtr&lt;CGContextRef&gt; context(AdoptCF, CGBitmapContextCreate(CFDataGetMutableBytePtr(data), CGImageGetWidth(referenceImage), CGImageGetHeight(referenceImage), 8, rowBytes, CGImageGetColorSpace(referenceImage), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
</ins><span class="cx"> 
</span><span class="cx">     CGContextSetBlendMode(context.get(), kCGBlendModeNormal);
</span><del>-    CGContextDrawImage(context.get(), CGRectMake(0, 0, static_cast&lt;CGFloat&gt;(CGImageGetWidth(testBitmap)), static_cast&lt;CGFloat&gt;(CGImageGetHeight(testBitmap))), testBitmap);
</del><ins>+    CGContextDrawImage(context.get(), CGRectMake(0, 0, static_cast&lt;CGFloat&gt;(CGImageGetWidth(testImage)), static_cast&lt;CGFloat&gt;(CGImageGetHeight(testImage))), testImage);
</ins><span class="cx">     CGContextSetBlendMode(context.get(), kCGBlendModeDifference);
</span><del>-    CGContextDrawImage(context.get(), CGRectMake(0, 0, static_cast&lt;CGFloat&gt;(CGImageGetWidth(referenceBitmap)), static_cast&lt;CGFloat&gt;(CGImageGetHeight(referenceBitmap))), referenceBitmap);
</del><ins>+    CGContextDrawImage(context.get(), CGRectMake(0, 0, static_cast&lt;CGFloat&gt;(CGImageGetWidth(referenceImage)), static_cast&lt;CGFloat&gt;(CGImageGetHeight(referenceImage))), referenceImage);
</ins><span class="cx"> 
</span><span class="cx">     return context;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-/**
- * Counts the number of non-black pixels, and returns the percentage
- * of non-black pixels to total pixels in the image.
- */
</del><ins>+// Counts the number of non-black pixels, and returns the percentage of non-black pixels to total pixels in the image.
</ins><span class="cx"> static float computePercentageDifferent(CGContextRef diffBitmap, unsigned threshold)
</span><span class="cx"> {
</span><del>-    // if diffBiatmap is nil, then there was an error, and it didn't match.
</del><ins>+    // if diffBitmap is nil, then there was an error, and it didn't match.
</ins><span class="cx">     if (!diffBitmap)
</span><span class="cx">         return 100.0f;
</span><span class="cx"> 
</span><span class="lines">@@ -108,7 +119,6 @@
</span><span class="cx">     unsigned char* pixelRowData = static_cast&lt;unsigned char*&gt;(CGBitmapContextGetData(diffBitmap));
</span><span class="cx">     unsigned differences = 0;
</span><span class="cx"> 
</span><del>-    // NOTE: This may not be safe when switching between ENDIAN types
</del><span class="cx">     for (unsigned row = 0; row &lt; pixelsHigh; row++) {
</span><span class="cx">         for (unsigned col = 0; col &lt; (pixelsWide * 4); col += 4) {
</span><span class="cx">             unsigned char* red = pixelRowData + col;
</span><span class="lines">@@ -130,10 +140,10 @@
</span><span class="cx">     return (differences * 100.f) / totalPixels;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void compareImages(CGImageRef actualBitmap, CGImageRef baselineBitmap, unsigned threshold)
</del><ins>+static void compareImages(CGImageRef testImage, CGImageRef referenceImage, unsigned threshold)
</ins><span class="cx"> {
</span><span class="cx">     // prepare the difference blend to check for pixel variations
</span><del>-    RetainPtr&lt;CGContextRef&gt; diffBitmap = getDifferenceBitmap(actualBitmap, baselineBitmap);
</del><ins>+    RetainPtr&lt;CGContextRef&gt; diffBitmap = createDifferenceBitmap(testImage, referenceImage);
</ins><span class="cx"> 
</span><span class="cx">     float percentage = computePercentageDifferent(diffBitmap.get(), threshold);
</span><span class="cx"> 
</span><span class="lines">@@ -142,13 +152,16 @@
</span><span class="cx">     // send message to let them know if an image was wrong
</span><span class="cx">     if (percentage &gt; 0.0f) {
</span><span class="cx">         // since the diff might actually show something, send it to stdout
</span><del>-        RetainPtr&lt;CGImageRef&gt; image(AdoptCF, CGBitmapContextCreateImage(diffBitmap.get()));
-        RetainPtr&lt;CFMutableDataRef&gt; imageData(AdoptCF, CFDataCreateMutable(0, 0));
-        RetainPtr&lt;CGImageDestinationRef&gt; imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0));
-        CGImageDestinationAddImage(imageDest.get(), image.get(), 0);
-        CGImageDestinationFinalize(imageDest.get());
-        printf(&quot;Content-Length: %lu\n&quot;, CFDataGetLength(imageData.get()));
-        fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout);
</del><ins>+        if (diffBitmap) {
+            RetainPtr&lt;CGImageRef&gt; image(AdoptCF, CGBitmapContextCreateImage(diffBitmap.get()));
+            RetainPtr&lt;CFMutableDataRef&gt; imageData(AdoptCF, CFDataCreateMutable(0, 0));
+            RetainPtr&lt;CGImageDestinationRef&gt; imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0));
+            CGImageDestinationAddImage(imageDest.get(), image.get(), 0);
+            CGImageDestinationFinalize(imageDest.get());
+            printf(&quot;Content-Length: %lu\n&quot;, CFDataGetLength(imageData.get()));
+            fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout);
+        }
+        
</ins><span class="cx">         fprintf(stdout, &quot;diff: %01.2f%% failed\n&quot;, percentage);
</span><span class="cx">     } else
</span><span class="cx">         fprintf(stdout, &quot;diff: %01.2f%% passed\n&quot;, percentage);
</span></span></pre>
</div>
</div>

</body>
</html>