2006-03-13 Eric Seidel <eseidel@apple.com>
authoreseidel <eseidel@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Mar 2006 04:50:09 +0000 (04:50 +0000)
committereseidel <eseidel@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Mar 2006 04:50:09 +0000 (04:50 +0000)
        Reviewed by mjs.

        Fix checksum generation on Intel machines.
        Also moved to CGImage APIs instead of NSBitmapImageRep, may possibly
        give a small speed boost now that it uses a shared buffer.

        * DumpRenderTree/DumpRenderTree.m:
        (main):
        (dump):
        (md5HashStringForBitmap):
        * DumpRenderTree/ImageDiff.m:
        (computePercentageDifferent):

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

WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/DumpRenderTree.m
WebKitTools/DumpRenderTree/ImageDiff.m

index af2e62128d0931d09b2e4c212a7ecf6042d52590..b99bd0aace20207928ea6a698f693b9c5f18bcfd 100644 (file)
@@ -1,3 +1,18 @@
+2006-03-13  Eric Seidel  <eseidel@apple.com>
+
+        Reviewed by mjs.
+
+        Fix checksum generation on Intel machines.
+        Also moved to CGImage APIs instead of NSBitmapImageRep, may possibly
+        give a small speed boost now that it uses a shared buffer.
+
+        * DumpRenderTree/DumpRenderTree.m:
+        (main):
+        (dump):
+        (md5HashStringForBitmap):
+        * DumpRenderTree/ImageDiff.m:
+        (computePercentageDifferent):
+
 2006-03-13  Darin Adler  <darin@apple.com>
 
         Reviewed by Tim Hatcher.
index c306dfd4173631a6c16348aa16b601f39039f388..025f542e954aa559d265949a202d8fe36115a6ec 100644 (file)
@@ -99,7 +99,7 @@
 @end
 
 static void dumpRenderTree(const char *pathOrURL);
-static NSString *md5HashStringForBitmap(NSBitmapImageRep *bitmap);
+static NSString *md5HashStringForBitmap(CGImageRef bitmap);
 
 static volatile BOOL done;
 static WebFrame *frame;
@@ -116,6 +116,11 @@ static NSPasteboard *localPasteboard;
 static BOOL windowIsKey = YES;
 static NSPoint lastMousePosition;
 static DumpRenderTreeDraggingInfo *draggingInfo;
+static unsigned char* screenCaptureBuffer;
+static CGColorSpaceRef sharedColorSpace;
+
+const unsigned maxViewHeight = 600;
+const unsigned maxViewWidth = 800;
 
 static CMProfileRef currentColorProfile = 0;
 static void restoreColorSpace(int ignored)
@@ -244,13 +249,16 @@ int main(int argc, const char *argv[])
         exit(1);
     }
     
-    if (dumpPixels)
+    if (dumpPixels) {
         setDefaultColorProfileToRGB();
+        screenCaptureBuffer = malloc(maxViewHeight * maxViewWidth * 4);
+        sharedColorSpace = CGColorSpaceCreateDeviceRGB();
+    }
     
     localPasteboard = [NSPasteboard pasteboardWithUniqueName];
     navigationController = [[NavigationController alloc] init];
 
-    NSRect rect = NSMakeRect(0, 0, 800, 600);
+    NSRect rect = NSMakeRect(0, 0, maxViewWidth, maxViewHeight);
     
     WebView *webView = [[WebView alloc] initWithFrame:rect];
     WaitUntilDoneDelegate *delegate = [[WaitUntilDoneDelegate alloc] init];
@@ -260,7 +268,7 @@ int main(int argc, const char *argv[])
     [webView setUIDelegate:delegate];
     frame = [webView mainFrame];
     
-    NSString *pwd = [[NSString stringWithCString:argv[0]] stringByDeletingLastPathComponent];
+    NSString *pwd = [[NSString stringWithUTF8String:argv[0]] stringByDeletingLastPathComponent];
     [WebPluginDatabase setAdditionalWebPlugInPaths:[NSArray arrayWithObject:pwd]];
     [[WebPluginDatabase installedPlugins] refresh];
 
@@ -348,7 +356,7 @@ static void dump(void)
             if (isSVGW3CTest)
                 [[frame webView] setFrameSize:NSMakeSize(480, 360)];
             else 
-                [[frame webView] setFrameSize:NSMakeSize(800, 600)];
+                [[frame webView] setFrameSize:NSMakeSize(maxViewWidth, maxViewHeight)];
             result = [frame renderTreeAsExternalRepresentation];
         }
         
@@ -374,20 +382,33 @@ static void dump(void)
             
             // grab a bitmap from the view
             WebView *view = [frame webView];
-            NSBitmapImageRep *imageRep = [view bitmapImageRepForCachingDisplayInRect:[view frame]];
-            [view cacheDisplayInRect:[view frame] toBitmapImageRep:imageRep];
+            NSSize webViewSize = [[frame webView] frame].size;
+            CGContextRef cgContext = CGBitmapContextCreate(screenCaptureBuffer, webViewSize.width, webViewSize.height, 8, webViewSize.width * 4, sharedColorSpace, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast);
+            NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:NO];
+            [NSGraphicsContext saveGraphicsState];
+            [NSGraphicsContext setCurrentContext:nsContext];
+            [view displayRectIgnoringOpacity:NSMakeRect(0, 0, webViewSize.width, webViewSize.height) inContext:nsContext];
+            [NSGraphicsContext restoreGraphicsState];
             
             // has the actual hash to compare to the expected image's hash
-            NSString *actualHash = md5HashStringForBitmap(imageRep);
+            CGImageRef bitmapImage = CGBitmapContextCreateImage(cgContext);
+            NSString *actualHash = md5HashStringForBitmap(bitmapImage);
             printf("\nActualHash: %s\n", [actualHash UTF8String]);
             printf("BaselineHash: %s\n", [baselineHash UTF8String]);
             
             // if the hashes don't match, send image back to stdout for diff comparision
-            if (![baselineHash isEqualToString:actualHash] || access([baselineImagePath fileSystemRepresentation], F_OK) != 0) {            
-                NSData *imageData = [imageRep representationUsingType:NSPNGFileType properties:nil];
-                printf("Content-length: %d\n", [imageData length]);
-                fwrite([imageData bytes], 1, [imageData length], stdout);
+            if (![baselineHash isEqualToString:actualHash] || access([baselineImagePath fileSystemRepresentation], F_OK) != 0) {
+                CFMutableDataRef imageData = CFDataCreateMutable(0, 0);
+                CGImageDestinationRef imageDest = CGImageDestinationCreateWithData(imageData, CFSTR("public.png"), 1, 0);
+                CGImageDestinationAddImage(imageDest, bitmapImage, 0);
+                CGImageDestinationFinalize(imageDest);
+                CFRelease(imageDest);
+                printf("Content-length: %lu\n", CFDataGetLength(imageData));
+                fwrite(CFDataGetBytePtr(imageData), 1, CFDataGetLength(imageData), stdout);
+                CFRelease(imageData);
             }
+            CGImageRelease(bitmapImage);
+            CGContextRelease(cgContext);
         }
 
         printf("#EOF\n");
@@ -888,13 +909,25 @@ static void dumpRenderTree(const char *pathOrURL)
 }
 
 /* Hashes a bitmap and returns a text string for comparison and saving to a file */
-static NSString *md5HashStringForBitmap(NSBitmapImageRep *bitmap)
+static NSString *md5HashStringForBitmap(CGImageRef bitmap)
 {
     MD5_CTX md5Context;
     unsigned char hash[16];
-
+    
+    unsigned bitsPerPixel = CGImageGetBitsPerPixel(bitmap);
+    assert(bitsPerPixel == 32); // ImageDiff assumes 32 bit RGBA, we must as well.
+    unsigned bytesPerPixel = bitsPerPixel / 8;
+    unsigned pixelsHigh = CGImageGetHeight(bitmap);
+    unsigned pixelsWide = CGImageGetWidth(bitmap);
+    unsigned bytesPerRow = CGImageGetBytesPerRow(bitmap);
+    assert(bytesPerRow >= (pixelsWide * bytesPerPixel));
+    
     MD5_Init(&md5Context);
-    MD5_Update(&md5Context, [bitmap bitmapData], [bitmap bytesPerPlane]);
+    unsigned char *bitmapData = screenCaptureBuffer;
+    for (unsigned row = 0; row < pixelsHigh; row++) {
+        MD5_Update(&md5Context, bitmapData, pixelsWide * bytesPerPixel);
+        bitmapData += bytesPerRow;
+    }
     MD5_Final(hash, &md5Context);
     
     char hex[33] = "";
index 6028c59ba5027a4e5827c3d45df4963b0dce9ce6..31811653a009228e9c0f813ee23613a364a009ad 100644 (file)
@@ -164,17 +164,26 @@ float computePercentageDifferent(NSBitmapImageRep *diffBitmap)
     // if diffBiatmap is nil, then there was an error, and it didn't match.
     if (diffBitmap == nil)
         return 100.0;
-        
-    int totalPixels = [diffBitmap pixelsHigh] * [diffBitmap pixelsWide];
-    int totalBytes = [diffBitmap bytesPerRow] * [diffBitmap pixelsHigh];
-    unsigned char *bitmapData = [diffBitmap bitmapData];
-    int differences = 0;
+    
+    unsigned bitmapFormat = [diffBitmap bitmapFormat];
+    assert(!(bitmapFormat & NSAlphaFirstBitmapFormat));
+    assert(!(bitmapFormat & NSFloatingPointSamplesBitmapFormat));
+    
+    unsigned pixelsHigh = [diffBitmap pixelsHigh];
+    unsigned pixelsWide = [diffBitmap pixelsWide];
+    unsigned bytesPerRow = [diffBitmap bytesPerRow];
+    unsigned char *pixelRowData = [diffBitmap bitmapData];
+    unsigned differences = 0;
     
     // NOTE: This may not be safe when switching between ENDIAN types
-    for (int i = 0; i < totalBytes; i += 4) {
-        if (*(bitmapData + i) != 0 || *(bitmapData + i + 1) != 0 || *(bitmapData + i + 2) != 0)
-            differences++;
+    for (unsigned row = 0; row < pixelsHigh; row++) {
+        for (unsigned col = 0; col < (pixelsWide * 4); col += 4) {
+            if (*(pixelRowData + col) != 0 || *(pixelRowData + col + 1) != 0 || *(pixelRowData + col + 2) != 0)
+                differences++;
+        }
+        pixelRowData += bytesPerRow;
     }
     
-    return (differences * 100.0)/totalPixels;
+    float totalPixels = pixelsHigh * pixelsWide;
+    return (differences * 100.f) / totalPixels;
 }