/*
 * Copyright (C) 2004 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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. 
 */
#import "loader.h"

#import "KWQPixmap.h"
#import "KWQFoundationExtras.h"

#import "WebCoreImageRenderer.h"
#import "WebCoreImageRendererFactory.h"

QPixmap *KWQLoadPixmap(const char *name)
{
    QPixmap *p = new QPixmap([[WebCoreImageRendererFactory sharedFactory] imageRendererWithName:[NSString stringWithCString:name]]);
    return p;
}

bool canRenderImageType(const QString &type)
{
    return [[[WebCoreImageRendererFactory sharedFactory] supportedMIMETypes] containsObject:type.getNSString()];
}

QPixmap::QPixmap()
{
    imageRenderer = nil;
    MIMEType = nil;
    needCopyOnWrite = false;
}

QPixmap::QPixmap(WebCoreImageRendererPtr r)
{
    imageRenderer = KWQRetain(r);
    MIMEType = nil;
    needCopyOnWrite = false;
}

QPixmap::QPixmap(void *MIME)
{
    imageRenderer = nil;
    MIMEType = KWQRetainNSRelease([(NSString *)MIME copy]);
    needCopyOnWrite = false;
}

QPixmap::QPixmap(const QSize &sz)
{
    imageRenderer = KWQRetain([[WebCoreImageRendererFactory sharedFactory] imageRendererWithSize:NSMakeSize(sz.width(), sz.height())]);
    MIMEType = nil;
    needCopyOnWrite = false;
}

QPixmap::QPixmap(const QByteArray &bytes)
{
    imageRenderer = KWQRetain([[WebCoreImageRendererFactory sharedFactory] imageRendererWithBytes:bytes.data() length:bytes.size()]);
    MIMEType = nil;
    needCopyOnWrite = false;
}

QPixmap::QPixmap(const QByteArray &bytes, NSString *MIME)
{
    MIMEType = KWQRetainNSRelease([MIME copy]);
    imageRenderer = KWQRetain([[WebCoreImageRendererFactory sharedFactory] imageRendererWithBytes:bytes.data() length:bytes.size() MIMEType:MIMEType]);
    needCopyOnWrite = false;
}

QPixmap::QPixmap(int w, int h)
{
    imageRenderer = KWQRetain([[WebCoreImageRendererFactory sharedFactory] imageRendererWithSize:NSMakeSize(w, h)]);
    MIMEType = nil;
    needCopyOnWrite = false;
}

QPixmap::QPixmap(const QPixmap &copyFrom) : QPaintDevice(copyFrom)
{
#if BUILDING_ON_PANTHER
    imageRenderer = KWQRetain(copyFrom.imageRenderer);
    copyFrom.needCopyOnWrite = true;
    needCopyOnWrite = true;
#else
    imageRenderer = KWQRetainNSRelease([copyFrom.imageRenderer copyWithZone:NULL]);;
    needCopyOnWrite = false;
#endif
    MIMEType = KWQRetainNSRelease([copyFrom.MIMEType copy]);
}

QPixmap::~QPixmap()
{
    KWQRelease(MIMEType);
    KWQRelease(imageRenderer);
}

CGImageRef QPixmap::imageRef()
{
    return [imageRenderer imageRef];
}

void QPixmap::resetAnimation()
{
    if (imageRenderer) {
        [imageRenderer resetAnimation];
    }
}


#if !defined(BUILDING_ON_PANTHER)
@interface WebImageCallback : NSObject
{
    khtml::CachedImageCallback *callback;
    CGImageSourceStatus status;
}
- (void)notify;
- (void)setImageSourceStatus:(CGImageSourceStatus)status;
- (CGImageSourceStatus)status;
@end
@implementation WebImageCallback
- initWithCallback:(khtml::CachedImageCallback *)c
{
    self = [super init];
    callback = c;
    c->ref();
    return self;
}

- (void)_commonTermination
{
    callback->deref();
}

- (void)dealloc
{
    [self _commonTermination];
    [super dealloc];
}

- (void)finalize
{
    [self _commonTermination];
    [super finalize];
}

- (void)notify
{
    if (status < kCGImageStatusReadingHeader)
        callback->notifyDecodingError();
    else if (status == kCGImageStatusIncomplete) {
        callback->notifyUpdate();
    }
    else if (status == kCGImageStatusComplete) {
        callback->notifyFinished();
    }
}

- (void)setImageSourceStatus:(CGImageSourceStatus)s
{
    status = s;
}

- (CGImageSourceStatus)status
{
    return status;
}

@end
#endif

bool QPixmap::shouldUseThreadedDecoding()
{
    return [WebCoreImageRendererFactory shouldUseThreadedDecoding] ? true : false;
}

bool QPixmap::receivedData(const QByteArray &bytes, bool isComplete, khtml::CachedImageCallback *decoderCallback)
{
    if (imageRenderer == nil) {
        imageRenderer = KWQRetain([[WebCoreImageRendererFactory sharedFactory] imageRendererWithMIMEType:MIMEType]);
    }
    
#if !defined(BUILDING_ON_PANTHER)
    WebImageCallback *callbackWrapper = 0;
    if (decoderCallback)
        callbackWrapper = [[WebImageCallback alloc] initWithCallback:decoderCallback];

    bool result = [imageRenderer incrementalLoadWithBytes:bytes.data() length:bytes.size() complete:isComplete callback:callbackWrapper];

    [callbackWrapper release];
#else
    bool result = [imageRenderer incrementalLoadWithBytes:bytes.data() length:bytes.size() complete:isComplete callback:0];
#endif
    
    return result;
}

bool QPixmap::mask() const
{
    return false;
}

bool QPixmap::isNull() const
{
    return imageRenderer == nil || [imageRenderer isNull];
}

QSize QPixmap::size() const
{
    if (imageRenderer == nil) {
        return QSize(0, 0);
    }
    NSSize sz = [imageRenderer size];
    return QSize((int)sz.width, (int)sz.height);
}

QRect QPixmap::rect() const
{
    if (imageRenderer == nil) {
        return QRect(0, 0, 0, 0);
    }
    NSSize sz = [imageRenderer size];
    return QRect(0, 0, (int)sz.width, (int)sz.height);
}

int QPixmap::width() const
{
    if (imageRenderer == nil) {
        return 0;
    }
    return (int)[imageRenderer size].width;
}

int QPixmap::height() const
{
    if (imageRenderer == nil) {
        return 0;
    }
    return (int)[imageRenderer size].height;
}

void QPixmap::resize(const QSize &sz)
{
    resize(sz.width(), sz.height());
}

void QPixmap::resize(int w, int h)
{
    if (needCopyOnWrite) {
        id <WebCoreImageRenderer> newImageRenderer = KWQRetainNSRelease([imageRenderer copyWithZone:NULL]);
        KWQRelease(imageRenderer);
        imageRenderer = newImageRenderer;
        needCopyOnWrite = false;
    }
    [imageRenderer resize:NSMakeSize(w, h)];
}

QPixmap QPixmap::xForm(const QWMatrix &xmatrix) const
{
    // This function is only called when an image needs to be scaled.  
    // We can depend on render_image.cpp to call resize AFTER
    // creating a copy of the image to be scaled. So, this
    // implementation simply returns a copy of the image. Note,
    // this assumption depends on the implementation of
    // RenderImage::printObject.   
    return *this;
}

QPixmap &QPixmap::operator=(const QPixmap &assignFrom)
{
    id <WebCoreImageRenderer> oldImageRenderer = imageRenderer;
    imageRenderer = KWQRetainNSRelease([assignFrom.imageRenderer retainOrCopyIfNeeded]);
    KWQRelease(oldImageRenderer);
    NSString *newMIMEType = KWQRetainNSRelease([assignFrom.MIMEType copy]);
    KWQRelease(MIMEType);
    MIMEType = newMIMEType;
    assignFrom.needCopyOnWrite = true;
    needCopyOnWrite = true;
    return *this;
}

void QPixmap::increaseUseCount() const
{
    [imageRenderer increaseUseCount];
}

void QPixmap::decreaseUseCount() const
{
    [imageRenderer decreaseUseCount];
}

void QPixmap::stopAnimations()
{
    [imageRenderer stopAnimation];
}

void QPixmap::flushRasterCache()
{
    [imageRenderer flushRasterCache];
}
