Alternate implementation of image rendering. Use CGImageRefs instead
authorrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Sep 2004 02:31:28 +0000 (02:31 +0000)
committerrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Sep 2004 02:31:28 +0000 (02:31 +0000)
        of NSImages.

        Mostly works, but currently disabled because of issues w/ CG.

        Reviewed by Chris.

        * ChangeLog:
        * WebCoreSupport.subproj/WebImageData.h: Added.
        * WebCoreSupport.subproj/WebImageData.m: Added.
        (-[WebImageData _commonTermination]):
        (-[WebImageData dealloc]):
        (-[WebImageData finalize]):
        (-[WebImageData copyWithZone:]):
        (-[WebImageData numberOfImages]):
        (-[WebImageData currentFrame]):
        (-[WebImageData _invalidateImages]):
        (-[WebImageData imageAtIndex:]):
        (-[WebImageData incrementalLoadWithBytes:length:complete:]):
        (drawPattern):
        (-[WebImageData tileInRect:fromPoint:context:]):
        (-[WebImageData isNull]):
        (-[WebImageData size]):
        (-[WebImageData _frameDuration]):
        (-[WebImageData _repetitionCount]):
        (-[WebImageData isAnimationFinished]):
        (+[WebImageData stopAnimationsInView:]):
        (-[WebImageData addAnimatingRenderer:inView:]):
        (-[WebImageData removeAnimatingRenderer:]):
        (-[WebImageData _stopAnimation]):
        (-[WebImageData _nextFrame:]):
        (-[WebImageData animate]):
        * WebCoreSupport.subproj/WebImageRenderer.h:
        * WebCoreSupport.subproj/WebImageRenderer.m:
        (-[WebImageRenderer initWithMIMEType:]):
        (-[WebImageRenderer initWithData:MIMEType:]):
        (-[WebImageRenderer initWithContentsOfFile:]):
        (-[WebImageRenderer dealloc]):
        (-[WebImageRenderer copyWithZone:]):
        (-[WebImageRenderer retainOrCopyIfNeeded]):
        (-[WebImageRenderer resize:]):
        (-[WebImageRenderer size]):
        (-[WebImageRenderer MIMEType]):
        (-[WebImageRenderer frameCount]):
        (-[WebImageRenderer isNull]):
        (-[WebImageRenderer incrementalLoadWithBytes:length:complete:]):
        (-[WebImageRenderer drawImageInRect:fromRect:]):
        (-[WebImageRenderer drawImageInRect:fromRect:compositeOperator:context:]):
        (-[WebImageRenderer tileInRect:fromPoint:context:]):
        (-[WebImageRenderer _startOrContinueAnimationIfNecessary]):
        (+[WebImageRenderer stopAnimationsInView:]):
        (-[WebImageRenderer stopAnimation]):
        (-[WebImageRenderer targetAnimationRect]):
        (-[WebImageRenderer increaseUseCount]):
        (-[WebImageRenderer decreaseUseCount]):
        (-[WebImageRenderer flushRasterCache]):
        (-[WebImageRenderer imageRef]):
        (-[WebImageRenderer TIFFRepresentation]):
        (-[WebImageRenderer image]):
        * WebCoreSupport.subproj/WebImageRendererFactory.m:
        (-[WebImageRendererFactory imageRendererWithMIMEType:]):
        (-[WebImageRendererFactory imageRendererWithData:MIMEType:]):
        (-[WebImageRendererFactory imageRendererWithSize:]):
        (-[WebImageRendererFactory imageRendererWithName:]):
        * WebKit.pbproj/project.pbxproj:
        * WebView.subproj/WebImageView.m:
        (-[WebImageView image]):

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

WebKit/ChangeLog
WebKit/Misc.subproj/WebNSViewExtras.m
WebKit/WebCoreSupport.subproj/WebImageData.h [new file with mode: 0644]
WebKit/WebCoreSupport.subproj/WebImageData.m [new file with mode: 0644]
WebKit/WebCoreSupport.subproj/WebImageRenderer.h
WebKit/WebCoreSupport.subproj/WebImageRenderer.m
WebKit/WebCoreSupport.subproj/WebImageRendererFactory.m
WebKit/WebKit.pbproj/project.pbxproj
WebKit/WebView.subproj/WebImageView.m

index d3b1d856c01f5d6180d686aaa14dcc60b8808b1e..8f7ca8a708b84b5e0e4a6ee55a7d8794e323b023 100644 (file)
@@ -1,3 +1,73 @@
+2004-09-09  Richard Williamson   <rjw@apple.com>
+
+        Alternate implementation of image rendering.  Use CGImageRefs instead
+        of NSImages.
+        
+        Mostly works, but currently disabled because of issues w/ CG.
+        
+        Reviewed by Chris.
+
+        * ChangeLog:
+        * WebCoreSupport.subproj/WebImageData.h: Added.
+        * WebCoreSupport.subproj/WebImageData.m: Added.
+        (-[WebImageData _commonTermination]):
+        (-[WebImageData dealloc]):
+        (-[WebImageData finalize]):
+        (-[WebImageData copyWithZone:]):
+        (-[WebImageData numberOfImages]):
+        (-[WebImageData currentFrame]):
+        (-[WebImageData _invalidateImages]):
+        (-[WebImageData imageAtIndex:]):
+        (-[WebImageData incrementalLoadWithBytes:length:complete:]):
+        (drawPattern):
+        (-[WebImageData tileInRect:fromPoint:context:]):
+        (-[WebImageData isNull]):
+        (-[WebImageData size]):
+        (-[WebImageData _frameDuration]):
+        (-[WebImageData _repetitionCount]):
+        (-[WebImageData isAnimationFinished]):
+        (+[WebImageData stopAnimationsInView:]):
+        (-[WebImageData addAnimatingRenderer:inView:]):
+        (-[WebImageData removeAnimatingRenderer:]):
+        (-[WebImageData _stopAnimation]):
+        (-[WebImageData _nextFrame:]):
+        (-[WebImageData animate]):
+        * WebCoreSupport.subproj/WebImageRenderer.h:
+        * WebCoreSupport.subproj/WebImageRenderer.m:
+        (-[WebImageRenderer initWithMIMEType:]):
+        (-[WebImageRenderer initWithData:MIMEType:]):
+        (-[WebImageRenderer initWithContentsOfFile:]):
+        (-[WebImageRenderer dealloc]):
+        (-[WebImageRenderer copyWithZone:]):
+        (-[WebImageRenderer retainOrCopyIfNeeded]):
+        (-[WebImageRenderer resize:]):
+        (-[WebImageRenderer size]):
+        (-[WebImageRenderer MIMEType]):
+        (-[WebImageRenderer frameCount]):
+        (-[WebImageRenderer isNull]):
+        (-[WebImageRenderer incrementalLoadWithBytes:length:complete:]):
+        (-[WebImageRenderer drawImageInRect:fromRect:]):
+        (-[WebImageRenderer drawImageInRect:fromRect:compositeOperator:context:]):
+        (-[WebImageRenderer tileInRect:fromPoint:context:]):
+        (-[WebImageRenderer _startOrContinueAnimationIfNecessary]):
+        (+[WebImageRenderer stopAnimationsInView:]):
+        (-[WebImageRenderer stopAnimation]):
+        (-[WebImageRenderer targetAnimationRect]):
+        (-[WebImageRenderer increaseUseCount]):
+        (-[WebImageRenderer decreaseUseCount]):
+        (-[WebImageRenderer flushRasterCache]):
+        (-[WebImageRenderer imageRef]):
+        (-[WebImageRenderer TIFFRepresentation]):
+        (-[WebImageRenderer image]):
+        * WebCoreSupport.subproj/WebImageRendererFactory.m:
+        (-[WebImageRendererFactory imageRendererWithMIMEType:]):
+        (-[WebImageRendererFactory imageRendererWithData:MIMEType:]):
+        (-[WebImageRendererFactory imageRendererWithSize:]):
+        (-[WebImageRendererFactory imageRendererWithName:]):
+        * WebKit.pbproj/project.pbxproj:
+        * WebView.subproj/WebImageView.m:
+        (-[WebImageView image]):
+
 === Safari-163 ===
 
 2004-09-09  Maciej Stachowiak  <mjs@apple.com>
index 6c64008f8e1f20b08a91f25706545322699a3d0d..8f58741d335660439950d6b8778c5d585366906e 100644 (file)
 }
 #endif
 
-- (void)_web_dragImage:(WebImageRenderer *)image
+- (void)_web_dragImage:(WebImageRenderer *)wir
                   rect:(NSRect)rect
                  event:(NSEvent *)event
             pasteboard:(NSPasteboard *)pasteboard 
     NSPoint mouseDownPoint = [self convertPoint:[event locationInWindow] fromView:nil];
     NSImage *dragImage;
     NSPoint origin;
+    NSImage *image;
     
+#ifdef USE_CGIMAGEREF
+    image = [wir image];
+#else
+    image = wir;
+#endif
     if ([image size].height * [image size].width <= WebMaxOriginalImageArea) {
         NSSize originalSize = rect.size;
         origin = rect.origin;
         origin.y = origin.y + originalSize.height;
         origin.y = mouseDownPoint.y - (((mouseDownPoint.y - origin.y) / originalSize.height) * newSize.height);
     } else {
-        NSString *extension = [[NSURLFileTypeMappings sharedMappings] preferredExtensionForMIMEType:[image MIMEType]];
+        NSString *extension = [[NSURLFileTypeMappings sharedMappings] preferredExtensionForMIMEType:[wir MIMEType]];
         if (extension == nil) {
             extension = @"";
         }
diff --git a/WebKit/WebCoreSupport.subproj/WebImageData.h b/WebKit/WebCoreSupport.subproj/WebImageData.h
new file mode 100644 (file)
index 0000000..d7745a6
--- /dev/null
@@ -0,0 +1,41 @@
+/*     WebImageData.h
+       Copyright 2004, Apple, Inc. All rights reserved.
+*/
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_3
+
+#import <Cocoa/Cocoa.h>
+
+// Needed for CGCompositeOperation
+#import <CoreGraphics/CGContextPrivate.h>
+
+@class WebImageRenderer;
+
+@interface WebImageData : NSObject <NSCopying>
+{
+    CGImageRef *images;
+    CGImageSourceRef imageSource;
+
+    CFMutableDictionaryRef animatingRenderers;
+    NSTimer *frameTimer;
+    size_t currentFrame;
+    int repetitionsComplete;
+    BOOL animationFinished;
+}
+
+- (size_t)numberOfImages;
+- (CGImageRef)imageAtIndex:(size_t)index;
+- (BOOL)incrementalLoadWithBytes:(const void *)bytes length:(unsigned)length complete:(BOOL)isComplete;
+- (void)drawImageAtIndex:(size_t)index inRect:(CGRect)ir fromRect:(CGRect)fr compositeOperation:(CGCompositeOperation)op context:(CGContextRef)aContext;
+- (void)tileInRect:(CGRect)rect fromPoint:(CGPoint)point context:(CGContextRef)aContext;
+- (BOOL)isNull;
+- (CGSize)size;
+- (void)animate;
++ (void)stopAnimationsInView:(NSView *)aView;
+- (void)addAnimatingRenderer:(WebImageRenderer *)r inView:(NSView *)view;
+- (void)removeAnimatingRenderer:(WebImageRenderer *)self;
+- (BOOL)isAnimationFinished;
+- (size_t)currentFrame;
+
+@end
+
+#endif
diff --git a/WebKit/WebCoreSupport.subproj/WebImageData.m b/WebKit/WebCoreSupport.subproj/WebImageData.m
new file mode 100644 (file)
index 0000000..b5ad21b
--- /dev/null
@@ -0,0 +1,484 @@
+/*     
+        WebImageData.m
+       Copyright (c) 2004 Apple, Inc. All rights reserved.
+*/
+#import <WebKit/WebAssertions.h>
+#import <WebKit/WebGraphicsBridge.h>
+#import <WebKit/WebImageData.h>
+#import <WebKit/WebImageRenderer.h>
+#import <WebKit/WebImageRendererFactory.h>
+
+#import <WebCore/WebCoreImageRenderer.h>
+
+#import <CoreGraphics/CGContextPrivate.h>
+#import <CoreGraphics/CGContextGState.h>
+
+#ifdef USE_CGIMAGEREF
+
+static CFDictionaryRef imageSourceOptions;
+
+// Forward declarations of internal methods.
+@interface WebImageData (WebInternal)
+- (void)_commonTermination;
+- (void)_invalidateImages;
+- (int)_repetitionCount;
+- (float)_frameDuration;
+- (void)_stopAnimation;
+- (void)_nextFrame;
+@end
+
+@implementation WebImageData
+
+- (void)_commonTermination
+{
+    ASSERT (!frameTimer);
+    
+    [self _invalidateImages];
+    
+    if (imageSource)
+        CFRelease (imageSource); 
+        
+    if (animatingRenderers)
+        CFRelease (animatingRenderers);
+}
+
+- (void)dealloc
+{
+    [self _commonTermination];
+
+    [super dealloc];
+}
+
+- (void)finalize
+{
+    [self _commonTermination];
+    [super finalize];
+}
+
+- copyWithZone:(NSZone *)zone
+{
+    WebImageData *copy;
+
+    copy = [[WebImageData alloc] init];
+    CFRetain (imageSource);
+    copy->imageSource = imageSource;
+    
+    return copy;
+}
+
+
+- (size_t)numberOfImages
+{
+    if (imageSource)
+        return CGImageSourceGetCount(imageSource);
+    return 0;
+}
+
+- (size_t)currentFrame
+{
+    return currentFrame;
+}
+
+- (void)_invalidateImages
+{
+    if (images) {
+        size_t i, count = [self numberOfImages];
+        for (i = 0; i < count; i++) {
+            if (images[i])
+                CFRelease (images[i]);
+        }
+        free (images);
+        images = 0;
+    }
+}
+
+- (CGImageRef)imageAtIndex:(size_t)index
+{
+    if (imageSource) {
+        if (index > [self numberOfImages])
+            return 0;
+
+        CGImageSourceStatus containerStatus = CGImageSourceGetStatus(imageSource);
+        if (containerStatus < kCGImageStatusIncomplete)
+            return 0;
+
+        CGImageSourceStatus imageStatus = CGImageSourceGetStatusAtIndex(imageSource, index);
+        if (imageStatus < kCGImageStatusIncomplete)
+            return 0;
+
+        if (!images) {
+            images = (CGImageRef *)calloc ([self numberOfImages], sizeof(CGImageRef *));
+        }
+            
+        if (!images[index]) {
+            if (!imageSourceOptions) {
+                CFStringRef keys[1] = { kCGImageSourceShouldCache };
+                CFBooleanRef values[1] = { kCFBooleanTrue };
+                imageSourceOptions = CFDictionaryCreate (NULL, (const void **)&keys, (const void **)&values, 1, 
+                            &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+            }
+            images[index] = CGImageSourceCreateImageAtIndex (imageSource, index, imageSourceOptions);
+            if (images[index] == 0)
+                ERROR ("unable to create image at index %d, containerStatus %d, image status %d", (int)index, containerStatus, imageStatus);
+        }
+        return images[index];
+    }
+    return 0;
+}
+
+- (BOOL)incrementalLoadWithBytes:(const void *)bytes length:(unsigned)length complete:(BOOL)isComplete
+{
+    if (!imageSource)
+        imageSource = CGImageSourceCreateIncremental (imageSourceOptions);
+
+    [self _invalidateImages];
+
+    CFDataRef data = CFDataCreate (NULL, bytes, length);
+    CGImageSourceUpdateData (imageSource, data, isComplete);
+    CFRelease (data);
+    
+    CGImageSourceStatus status = CGImageSourceGetStatus(imageSource);
+    
+    if (status < kCGImageStatusIncomplete) {
+        ERROR ("error update incremental image data, status %d", status);
+    }
+    
+    return status >= kCGImageStatusIncomplete;
+}
+
+- (void)drawImageAtIndex:(size_t)index inRect:(CGRect)ir fromRect:(CGRect)fr compositeOperation:(CGCompositeOperation)op context:(CGContextRef)aContext;
+{
+    CGImageRef image = [self imageAtIndex:index];
+    
+    if (!image)
+        return;
+
+    CGContextSaveGState (aContext);
+
+    float w = CGImageGetWidth(image);
+    float h = CGImageGetHeight(image);
+
+    // FIXME:  Need to determine number of available lines.
+    int numCompleteLines = h;
+
+    int pixelsHigh = h;
+    if (pixelsHigh > numCompleteLines) {
+        // Figure out how much of the image is OK to draw.  We can't simply
+        // use numCompleteLines because the image may be scaled.
+        float clippedImageHeight = floor([self size].height * numCompleteLines / pixelsHigh);
+        
+        // Figure out how much of the source is OK to draw from.
+        float clippedSourceHeight = clippedImageHeight - fr.origin.y;
+        if (clippedSourceHeight < 1) {
+            return;
+        }
+        
+        // Figure out how much of the destination we are going to draw to.
+        float clippedDestinationHeight = ir.size.height * clippedSourceHeight / fr.size.height;
+
+        // Reduce heights of both rectangles without changing their positions.
+        // In the flipped case, just adjusting the height is sufficient.
+        ir.size.height = clippedDestinationHeight;
+        fr.size.height = clippedSourceHeight;
+    }
+
+    CGContextSetCompositeOperation (aContext, op);
+    CGContextTranslateCTM (aContext, ir.origin.x, ir.origin.y);
+    CGContextScaleCTM (aContext, 1, -1);
+    CGContextTranslateCTM (aContext, 0, -h);
+    
+    // Translated to origin, now draw at 0,0.
+    ir.origin.x = ir.origin.y = 0;
+        
+    if (fr.size.width != w || fr.size.height != h) {
+        //image = CGImageCreateWithImageInRect (image, fr);
+        //if (image) {
+        //    CGContextDrawImage (aContext, ir, image);
+        //    CFRelease (image);
+        //}
+        
+        // FIXME:  Until the API above is implemented (CGImageCreateWithImageInRect), we
+        // must create our own subimage.
+        //
+        // Create a new bitmap of the appropriate size and then draw that into our context.
+        // Slo, boo!
+        CGContextRef clippedSourceContext;
+        CGImageRef clippedSourceImage;
+        size_t csw = (size_t)fr.size.width;
+        size_t csh = (size_t)fr.size.height;
+                            
+        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+        size_t numComponents = CGColorSpaceGetNumberOfComponents(colorSpace);
+        size_t bytesPerRow = ((csw * 8 * (numComponents+1) + 7)/8); // + 1 for alpha
+        void *_drawingContextData = malloc(csh * bytesPerRow);
+        
+        // 8 bit per component
+        clippedSourceContext = CGBitmapContextCreate(_drawingContextData, csw, csh, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
+        CGContextTranslateCTM (clippedSourceContext, -fr.origin.x, -fr.origin.y);
+        CGContextDrawImage (clippedSourceContext, CGRectMake(0,0,w,h), image);
+        clippedSourceImage = CGBitmapContextCreateImage(clippedSourceContext);
+        CGContextDrawImage (aContext, ir, clippedSourceImage);
+        
+        CGImageRelease (clippedSourceImage);
+        CGContextRelease (clippedSourceContext);
+        free (_drawingContextData);
+    }
+    else { 
+        CGContextDrawImage (aContext, ir, image);
+    }
+
+    CGContextRestoreGState (aContext);
+}
+
+static void drawPattern (void * info, CGContextRef context)
+{
+    CGImageRef image = (CGImageRef)info;
+    float w = CGImageGetWidth(image);
+    float h = CGImageGetHeight(image);
+    CGContextDrawImage (context, CGRectMake(0, 0, w, h), image);    
+}
+
+CGPatternCallbacks patternCallbacks = { 0, drawPattern, NULL };
+
+- (void)tileInRect:(CGRect)rect fromPoint:(CGPoint)point context:(CGContextRef)aContext
+{
+    ASSERT (aContext);
+    
+    CGImageRef image = [self imageAtIndex:[self currentFrame]];
+    if (!image) {
+        ERROR ("unable to find image");
+        return;
+    }
+
+    float w = CGImageGetWidth(image);
+    float h = CGImageGetHeight(image);
+
+    // Check and see if a single draw of the image can cover the entire area we are supposed to tile.
+    NSRect oneTileRect;
+    oneTileRect.origin.x = rect.origin.x + fmodf(fmodf(-point.x, w) - w, w);
+    oneTileRect.origin.y = rect.origin.y + fmodf(fmodf(-point.y, h) - h, h);
+    oneTileRect.size.width = w;
+    oneTileRect.size.height = h;
+
+    // If the single image draw covers the whole area, then just draw once.
+    if (NSContainsRect(oneTileRect, NSMakeRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height))) {
+        CGRect fromRect;
+
+        fromRect.origin.x = rect.origin.x - oneTileRect.origin.x;
+        fromRect.origin.y = rect.origin.y - oneTileRect.origin.y;
+        fromRect.size = rect.size;
+        
+        [self drawImageAtIndex:[self currentFrame] inRect:rect fromRect:fromRect compositeOperation:kCGCompositeSover context:aContext];
+        return;
+    }
+
+    // Compute the appropriate phase relative to the top level view in the window.
+    // Conveniently, the oneTileRect we computed above has the appropriate origin.
+    NSPoint originInWindow = [[NSView focusView] convertPoint:oneTileRect.origin toView:nil];
+
+    // WebCore may translate the focus, and thus need an extra phase correction
+    NSPoint extraPhase = [[WebGraphicsBridge sharedBridge] additionalPatternPhase];
+    originInWindow.x += extraPhase.x;
+    originInWindow.y += extraPhase.y;
+    CGSize phase = CGSizeMake(fmodf(originInWindow.x, w), fmodf(originInWindow.y, h));
+
+    // Possible optimization:  We may want to cache the CGPatternRef    
+    CGPatternRef pattern = CGPatternCreate(image, CGRectMake (0, 0, w, h), CGAffineTransformIdentity, w, h, 
+        kCGPatternTilingConstantSpacing, true, &patternCallbacks);
+    if (pattern) {
+        CGContextSaveGState (aContext);
+
+        CGContextSetPatternPhase(aContext, phase);
+
+        CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
+        CGContextSetFillColorSpace(aContext, patternSpace);
+        CGColorSpaceRelease(patternSpace);
+
+        float patternAlpha = 1;
+        CGContextSetFillPattern(aContext, pattern, &patternAlpha);
+
+        CGContextSetCompositeOperation (aContext, kCGCompositeSover);
+
+        CGContextFillRect (aContext, rect);
+
+        CGPatternRelease (pattern);
+
+        CGContextRestoreGState (aContext);
+    }
+    else {
+        ERROR ("unable to create pattern");
+    }
+}
+
+- (BOOL)isNull
+{
+    CGImageSourceStatus status = CGImageSourceGetStatusAtIndex(imageSource, [self currentFrame]);
+    return status < kCGImageStatusIncomplete;
+}
+
+- (CGSize)size
+{
+    float w = 0.f, h = 0.f;
+    CGImageRef image = [self imageAtIndex:0];
+    if (image) {
+        h = CGImageGetHeight(image);
+        w = CGImageGetWidth(image);
+    }
+    return CGSizeMake(w,h);
+}
+
+#define MINIMUM_DURATION (1.0/30.0)
+
+- (float)_frameDuration
+{
+    CFDictionaryRef properties = CGImageSourceGetPropertiesAtIndex (imageSource, currentFrame, 0);
+    if (!properties)
+        return 0.f;
+        
+    // FIXME:  Use constant instead of {GIF}
+    CFDictionaryRef GIFProperties = CFDictionaryGetValue (properties, @"{GIF}");
+    if (!GIFProperties)
+        return 0.f;
+    
+    // FIXME:  Use constant instead of DelayTime
+    CFNumberRef num = CFDictionaryGetValue (GIFProperties, @"DelayTime");
+    if (!num)
+        return 0.f;
+    
+    float duration = 0.f;
+    CFNumberGetValue (num, kCFNumberFloat32Type, &duration);
+    if (duration < MINIMUM_DURATION) {
+        /*
+            Many annoying ads specify a 0 duration to make an image flash
+            as quickly as possible.  However a zero duration is faster than
+            the refresh rate.  We need to pick a minimum duration.
+            
+            Browsers handle the minimum time case differently.  IE seems to use something
+            close to 1/30th of a second.  Konqueror uses 0.  The ImageMagick library
+            uses 1/100th.  The units in the GIF specification are 1/100th of second.
+            We will use 1/30th of second as the minimum time.
+        */
+        duration = MINIMUM_DURATION;
+    }
+    return duration;
+}
+
+- (int)_repetitionCount
+{
+    // FIXME:  Need to get this from CG folks.
+    return 0;
+}
+
+- (BOOL)isAnimationFinished
+{
+    return animationFinished;
+}
+
+static NSMutableSet *activeAnimations;
+
++ (void)stopAnimationsInView:(NSView *)aView
+{
+    NSEnumerator *objectEnumerator = [activeAnimations objectEnumerator];
+    WebImageData *animation;
+    NSMutableSet *animationsToStop = [[NSMutableSet alloc] init];
+
+    while ((animation = [objectEnumerator nextObject])) {
+        if (CFDictionaryGetValue (animation->animatingRenderers, aView)) {
+            [animationsToStop addObject: animation];
+        }
+    }
+
+    objectEnumerator = [animationsToStop objectEnumerator];
+    while ((animation = [objectEnumerator nextObject])) {
+        CFDictionaryRemoveValue (animation->animatingRenderers, aView);
+        if (CFDictionaryGetCount(animation->animatingRenderers) == 0) {
+            [animation _stopAnimation];
+        }
+    }
+    [animationsToStop release];
+}
+
+- (void)addAnimatingRenderer:(WebImageRenderer *)r inView:(NSView *)view
+{
+    if (!animatingRenderers)
+        animatingRenderers = CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
+    
+    NSMutableSet *renderers = (NSMutableSet *)CFDictionaryGetValue (animatingRenderers, view);
+    if (!renderers) {
+        renderers = [[NSMutableSet alloc] init];
+        CFDictionaryAddValue(animatingRenderers, view, renderers);
+    }
+            
+    [renderers addObject:r];
+
+    if (!activeAnimations)
+        activeAnimations = [[NSMutableSet alloc] init];
+    [activeAnimations addObject:self];
+}
+
+- (void)removeAnimatingRenderer:(WebImageRenderer *)r
+{
+    NSEnumerator *viewEnumerator = [(NSMutableDictionary *)animatingRenderers keyEnumerator];
+    NSView *view;
+    while ((view = [viewEnumerator nextObject])) {
+        NSMutableSet *renderers = (NSMutableSet *)CFDictionaryGetValue (animatingRenderers, view);
+        [renderers removeObject:r];
+        if ([renderers count] == 0) {
+            CFDictionaryRemoveValue (animatingRenderers, renderers);
+        }
+    }
+    
+    if (animatingRenderers && CFDictionaryGetCount(animatingRenderers) == 0) {
+        [activeAnimations removeObject:self];
+    }
+}
+
+- (void)_stopAnimation
+{
+    [frameTimer invalidate];
+    [frameTimer release];
+    frameTimer = nil;
+}
+
+- (void)_nextFrame:(id)context
+{
+    // Release the timer that just fired.
+    [frameTimer release];
+    frameTimer = nil;
+    
+    currentFrame++;
+    if (currentFrame >= [self numberOfImages]) {
+        repetitionsComplete += 1;
+        if ([self _repetitionCount] && repetitionsComplete >= [self _repetitionCount]) {
+            animationFinished = YES;
+            return;
+        }
+        currentFrame = 0;
+    }
+    
+    NSEnumerator *viewEnumerator = [(NSMutableDictionary *)animatingRenderers keyEnumerator];
+    NSView *view;
+    while ((view = [viewEnumerator nextObject])) {
+        NSMutableSet *renderers = [(NSMutableDictionary *)animatingRenderers objectForKey:view];
+        WebImageRenderer *renderer;
+        NSEnumerator *rendererEnumerator = [renderers objectEnumerator];
+        while ((renderer = [rendererEnumerator nextObject])) {
+            [view setNeedsDisplayInRect:[renderer targetAnimationRect]];
+        }
+    }
+}
+
+- (void)animate
+{
+    if (frameTimer && [frameTimer isValid])
+        return;
+    frameTimer = [[NSTimer scheduledTimerWithTimeInterval:[self _frameDuration]
+                                                    target:self
+                                                  selector:@selector(_nextFrame:)
+                                                  userInfo:nil
+                                                   repeats:NO] retain];
+}
+
+@end
+
+#endif
index cae0169168937fe5445931dda8d35c64d7ed7a41..568535e1b6cbf5e752cbd5defd1922366b0999e1 100644 (file)
@@ -4,8 +4,47 @@
 
 #import <Cocoa/Cocoa.h>
 
+// Needed for CGCompositeOperation
+#import <CoreGraphics/CGContextPrivate.h>
+
 @protocol WebCoreImageRenderer;
 
+//#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_3
+//#define USE_CGIMAGEREF YES
+//#endif
+
+#ifdef USE_CGIMAGEREF
+@class WebImageData;
+
+@interface WebImageRenderer : NSObject <WebCoreImageRenderer>
+{
+    NSString *MIMEType;
+
+    WebImageData *imageData;
+
+    NSRect targetAnimationRect;
+    
+    NSSize adjustedSize;
+    BOOL isSizeAdjusted;
+}
+
+- (id)initWithMIMEType:(NSString *)MIME;
+- (id)initWithData:(NSData *)data MIMEType:(NSString *)MIME;
+- (id)initWithContentsOfFile:(NSString *)filename;
+- (NSString *)MIMEType;
++ (void)stopAnimationsInView:(NSView *)aView;
+- (int)frameCount;
+- (NSRect)targetAnimationRect;
+- (void)resize:(NSSize)s;
+- (NSSize)size;
+- (NSData *)TIFFRepresentation;
+- (NSImage *)image;
+
+@end
+
+#else
+
+
 @interface WebImageRenderer : NSImage <WebCoreImageRenderer>
 {
     NSTimer *frameTimer;
@@ -38,6 +77,7 @@
     CGImageRef cachedImageRef;
     
     id _PDFDoc;
+        
 @public    
     NSData *originalData;
 }
@@ -50,3 +90,5 @@
 - (NSString *)MIMEType;
 
 @end
+
+#endif
index 5e5cda8afe5f02d5d06e530b4fca9d020ebd6936..42487d422dfc0191a924cb60f4ceeaa2f7a87fc7 100644 (file)
@@ -2,7 +2,6 @@
         WebImageRenderer.m
        Copyright (c) 2002, 2003, Apple, Inc. All rights reserved.
 */
-
 #import <WebKit/WebImageRenderer.h>
 
 #import <WebKit/WebAssertions.h>
 
 #import <WebCore/WebCoreImageRenderer.h>
 
+#import <CoreGraphics/CGContextPrivate.h>
 #import <CoreGraphics/CGContextGState.h>
 
+
+#ifdef USE_CGIMAGEREF
+
+#import <WebKit/WebImageData.h>
+
+// Forward declarations of internal methods.
+@interface WebImageRenderer (WebInternal)
+- (void)_startOrContinueAnimationIfNecessary;
+@end
+
+@implementation WebImageRenderer
+
+- (id)initWithMIMEType:(NSString *)MIME
+{
+    self = [super init];
+    if (self != nil) {
+        MIMEType = [MIME copy];
+    }
+    return self;
+}
+
+- (id)initWithData:(NSData *)data MIMEType:(NSString *)MIME
+{
+    self = [super init];
+    if (self != nil) {
+        MIMEType = [MIME copy];
+        imageData = [[WebImageData alloc] init];
+        [imageData incrementalLoadWithBytes:[data bytes] length:[data length] complete:YES];
+    }
+    return self;
+}
+
+- (id)initWithContentsOfFile:(NSString *)filename
+{
+    self = [super init];
+
+    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
+    NSString *imagePath = [bundle pathForResource:filename ofType:@"tiff"];
+
+    imageData = [[WebImageData alloc] init];
+    NSData *data = [NSData dataWithContentsOfFile:imagePath];
+    [imageData incrementalLoadWithBytes:[data bytes] length:[data length] complete:YES];
+        
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [MIMEType release];
+    [imageData release];
+}
+
+- copyWithZone:(NSZone *)zone
+{
+    WebImageRenderer *copy;
+
+    copy = [[WebImageRenderer alloc] init];
+    copy->MIMEType = [MIMEType copy];
+    copy->adjustedSize = adjustedSize;
+    copy->isSizeAdjusted = isSizeAdjusted;
+    copy->imageData = [imageData retain];
+        
+    return copy;
+}
+
+- (id <WebCoreImageRenderer>)retainOrCopyIfNeeded
+{
+    return [self copyWithZone:0];
+}
+
+- (void)resize:(NSSize)s
+{
+    isSizeAdjusted = YES;
+    adjustedSize = s;
+}
+
+- (NSSize)size
+{
+    if (isSizeAdjusted)
+        return adjustedSize;
+        
+    CGSize sz = [imageData size];
+    return NSMakeSize(sz.width, sz.height);
+}
+
+- (NSString *)MIMEType
+{
+    return MIMEType;
+}
+
+- (int)frameCount
+{
+    return [imageData numberOfImages];
+}
+
+
+- (BOOL)isNull
+{
+    return [imageData isNull];
+}
+
+- (BOOL)incrementalLoadWithBytes:(const void *)bytes length:(unsigned)length complete:(BOOL)isComplete
+{
+    if (!imageData)
+        imageData = [[WebImageData alloc] init];
+    return [imageData incrementalLoadWithBytes:bytes length:length complete:isComplete];
+}
+
+- (void)drawImageInRect:(NSRect)ir fromRect:(NSRect)fr
+{
+    CGContextRef aContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+    CGCompositeOperation op = kCGCompositeSover;
+
+    [self drawImageInRect:ir fromRect:fr compositeOperator:op context:aContext];
+}
+
+- (void)drawImageInRect:(NSRect)ir fromRect:(NSRect)fr compositeOperator:(NSCompositingOperation)operator context:(CGContextRef)aContext
+{
+    if (aContext == 0)
+        aContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+    
+    CGCompositeOperation op = (CGCompositeOperation)operator;
+    if (op == kCGCompositeUnknown)
+        op = kCGCompositeSover;
+        
+    [imageData drawImageAtIndex:[imageData currentFrame] inRect:CGRectMake(ir.origin.x, ir.origin.y, ir.size.width, ir.size.height) 
+                    fromRect:CGRectMake(fr.origin.x, fr.origin.y, fr.size.width, fr.size.height) 
+                    compositeOperation:op context:aContext];
+
+    targetAnimationRect = ir;
+    [self _startOrContinueAnimationIfNecessary];
+}
+
+- (void)tileInRect:(NSRect)rect fromPoint:(NSPoint)point context:(CGContextRef)aContext
+{
+    if (aContext == 0)
+        aContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+
+    [imageData tileInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)
+            fromPoint:CGPointMake(point.x, point.y) context:aContext];
+            
+    targetAnimationRect = rect;
+    [self _startOrContinueAnimationIfNecessary];
+}
+
+- (void)_startOrContinueAnimationIfNecessary
+{
+    if ([imageData numberOfImages] > 1 && ![imageData isAnimationFinished]) {
+        [imageData addAnimatingRenderer:self inView:[NSView focusView]];
+        [imageData animate];
+    }
+}
+
++ (void)stopAnimationsInView:(NSView *)aView
+{
+    [WebImageData stopAnimationsInView:aView];
+}
+
+
+- (void)stopAnimation
+{
+    [imageData removeAnimatingRenderer:self];
+}
+
+- (NSRect)targetAnimationRect
+{
+    return targetAnimationRect;
+}
+
+- (void)increaseUseCount
+{
+}
+
+- (void)decreaseUseCount
+{
+}
+
+- (void)flushRasterCache
+{
+}
+
+- (CGImageRef)imageRef
+{
+    return [imageData imageAtIndex:0];
+}
+
+- (NSData *)TIFFRepresentation
+{
+    CGImageRef image = [imageData imageAtIndex:0];
+    if (!image)
+        return 0;
+        
+    CFMutableDataRef data = 0;
+    CGImageDestinationRef destination = 0;
+    
+    data = CFDataCreateMutable(NULL, 0);
+    // FIXME:  Use type kCGImageTypeIdentifierTIFF constant once is becomes available in the API
+    destination = CGImageDestinationCreateWithData (data, CFSTR("public.tiff"), 1, NULL);
+    if (destination) {
+        CGImageDestinationAddImage (destination, image, NULL);
+        CGImageDestinationFinalize (destination);
+        CFRelease (destination);
+    }
+
+    return [(NSData *)data autorelease];
+}
+
+- (NSImage *)image
+{
+    // FIXME:  Implement
+    return nil;
+}
+
+@end
+
+#else
+
 extern NSString *NSImageLoopCount;
 
 /*
@@ -155,6 +373,7 @@ static CGImageRef _createImageRef(NSBitmapImageRep *rep);
 - (BOOL)_PDFDrawFromRect:(NSRect)srcRect toRect:(NSRect)dstRect operation:(NSCompositingOperation)op alpha:(float)alpha flipped:(BOOL)flipped;
 @end
 
+
 @implementation WebImageRenderer
 
 static NSMutableSet *activeImageRenderers;
@@ -294,7 +513,7 @@ static NSMutableSet *activeImageRenderers;
     copy->patternColor = nil;
     copy->compositeOperator = compositeOperator;
     copy->context = 0;
-        
+
     return copy;
 }
 
@@ -856,7 +1075,6 @@ static NSMutableSet *activeImageRenderers;
     return ref;
 }
 
-
 @end
 
 
@@ -1014,3 +1232,4 @@ static CGImageRef _createImageRef(NSBitmapImageRep *rep) {
 
     return image;
 }
+#endif
index f79a5c9e8fb9377437e158864a6577982f46f9e7..436fc7abebca03b18e981120695fa9893bbdd562 100644 (file)
@@ -50,6 +50,7 @@
 {
     NSImage *imageRenderer = [[WebImageRenderer alloc] initWithMIMEType:MIMEType];
 
+#ifndef USE_CGIMAGEREF
     if (![MIMEType isEqual:@"application/pdf"]) {
         NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initForIncrementalLoad];
         [imageRenderer addRepresentation:rep];
@@ -65,6 +66,7 @@
     [imageRenderer setCacheMode: NSImageCacheNever];
 
     [imageRenderer setScalesWhenResized:NO];
+#endif
         
     return [imageRenderer autorelease];
 }
@@ -78,6 +80,7 @@
 {
     WebImageRenderer *imageRenderer = [[WebImageRenderer alloc] initWithData:data MIMEType:MIMEType];
 
+#ifndef USE_CGIMAGEREF
     NSArray *reps = [imageRenderer representations];
     if ([reps count] == 0){
         [imageRenderer release];
@@ -94,6 +97,7 @@
     }
     
     [imageRenderer setFlipped:YES];
+#endif
 
     return [imageRenderer autorelease];
 }
 - (id <WebCoreImageRenderer>)imageRendererWithSize:(NSSize)s
 {
     WebImageRenderer *imageRenderer = [[[WebImageRenderer alloc] initWithSize:s] autorelease];
+#ifndef USE_CGIMAGEREF
     [imageRenderer setScalesWhenResized:NO];
+#endif
     return imageRenderer;
 }
 
 - (id <WebCoreImageRenderer>)imageRendererWithName:(NSString *)name
 {
     WebImageRenderer *imageRenderer = [[[WebImageRenderer alloc] initWithContentsOfFile:name] autorelease];
+#ifndef USE_CGIMAGEREF
     [imageRenderer setScalesWhenResized:NO];
     [imageRenderer setFlipped:YES];
+#endif
     return imageRenderer;
 }
 
index 261bbd9d61f9a325b9c72266afe5acb3c1e19667..e4fce342d0e223344f637ba66aa703676dc3f7ef 100644 (file)
                                83634A7406DA5ECD0026E290,
                                93B641FC06E292BC0055F610,
                                EDE850CE06ECC79E005FAB05,
+                               51C6513806EFCD9300969825,
                        );
                        isa = PBXHeadersBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                                51E94C6B06C0347500A9B09E,
                                83634A7306DA5ECD0026E290,
                                93B641FB06E292BC0055F610,
+                               51C6513906EFCD9300969825,
                        );
                        isa = PBXSourcesBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                                );
                        };
                };
+               51C6513606EFCD9300969825 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WebImageData.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               51C6513706EFCD9300969825 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = WebImageData.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               51C6513806EFCD9300969825 = {
+                       fileRef = 51C6513606EFCD9300969825;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               51C6513906EFCD9300969825 = {
+                       fileRef = 51C6513706EFCD9300969825;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
                51E94C0706C02CA300A9B09E = {
                        children = (
                                51E94C6806C0347500A9B09E,
                                F5E7B24603025CE801A80180,
                                BE26F18D05517E0800BFA0C3,
                                BE26F18E05517E0800BFA0C3,
+                               51C6513606EFCD9300969825,
+                               51C6513706EFCD9300969825,
                                9CE1F8A002A5C6F30ECA2ACD,
                                9CE1F8A102A5C6F30ECA2ACD,
                                9CE1F8A202A5C6F30ECA2ACD,
index e2531b5125ae22315452eb9fa46583ac706eb319..b76fd6654c2ac96bbccdbca9ab01b981b8434292 100644 (file)
 
 - (NSImage *)image
 {
+#ifdef USE_CGIMAGEREF
+    return [[rep image] image];
+#else
     return [rep image];
+#endif
 }
 
 #pragma mark PRINTING