1/*
2 * Copyright (C) 2004, 2005, 2006 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "BitmapImage.h"
28
29#if USE(CG)
30
31#include "FloatConversion.h"
32#include "GraphicsContextCG.h"
33#include "ImageObserver.h"
34#include "SubimageCacheWithTimer.h"
35#include <ApplicationServices/ApplicationServices.h>
36#include <wtf/RetainPtr.h>
37
38#if PLATFORM(MAC)
39#include "WebCoreSystemInterface.h"
40#endif
41
42#if PLATFORM(WIN)
43#include <WebKitSystemInterface/WebKitSystemInterface.h>
44#endif
45
46namespace WebCore {
47
48bool FrameData::clear(bool clearMetadata)
49{
50    if (clearMetadata)
51        m_haveMetadata = false;
52
53    m_orientation = DefaultImageOrientation;
54
55    if (m_frame) {
56#if CACHE_SUBIMAGES
57        subimageCache().clearImage(m_frame);
58#endif
59        CGImageRelease(m_frame);
60        m_frame = 0;
61        return true;
62    }
63    return false;
64}
65
66BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
67    : Image(observer)
68    , m_currentFrame(0)
69    , m_frames(0)
70    , m_frameTimer(0)
71    , m_repetitionCount(cAnimationNone)
72    , m_repetitionCountStatus(Unknown)
73    , m_repetitionsComplete(0)
74    , m_decodedSize(0)
75    , m_decodedPropertiesSize(0)
76    , m_frameCount(1)
77    , m_isSolidColor(false)
78    , m_checkedForSolidColor(false)
79    , m_animationFinished(true)
80    , m_allDataReceived(true)
81    , m_haveSize(true)
82    , m_sizeAvailable(true)
83    , m_haveFrameCount(true)
84{
85    CGFloat width = CGImageGetWidth(cgImage);
86    CGFloat height = CGImageGetHeight(cgImage);
87    m_decodedSize = width * height * 4;
88    m_size = IntSize(width, height);
89
90    // Since we don't have a decoder, we can't figure out the image orientation.
91    // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0.
92    m_sizeRespectingOrientation = IntSize(width, height);
93
94    m_frames.grow(1);
95    m_frames[0].m_frame = cgImage;
96    m_frames[0].m_hasAlpha = true;
97    m_frames[0].m_haveMetadata = true;
98
99    checkForSolidColor();
100}
101
102// Drawing Routines
103
104void BitmapImage::checkForSolidColor()
105{
106    m_checkedForSolidColor = true;
107    if (frameCount() > 1) {
108        m_isSolidColor = false;
109        return;
110    }
111
112    CGImageRef image = frameAtIndex(0);
113
114    // Currently we only check for solid color in the important special case of a 1x1 image.
115    if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
116        unsigned char pixel[4]; // RGBA
117        RetainPtr<CGContextRef> bmap = adoptCF(CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), deviceRGBColorSpaceRef(),
118            kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big));
119        if (!bmap)
120            return;
121        GraphicsContext(bmap.get()).setCompositeOperation(CompositeCopy);
122        CGRect dst = { {0, 0}, {1, 1} };
123        CGContextDrawImage(bmap.get(), dst, image);
124        if (pixel[3] == 0)
125            m_solidColor = Color(0, 0, 0, 0);
126        else
127            m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]);
128        m_isSolidColor = true;
129    }
130}
131
132CGImageRef BitmapImage::getCGImageRef()
133{
134    return frameAtIndex(0);
135}
136
137CGImageRef BitmapImage::getFirstCGImageRefOfSize(const IntSize& size)
138{
139    size_t count = frameCount();
140    for (size_t i = 0; i < count; ++i) {
141        CGImageRef cgImage = frameAtIndex(i);
142        if (cgImage && IntSize(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)) == size)
143            return cgImage;
144    }
145
146    // Fallback to the default CGImageRef if we can't find the right size
147    return getCGImageRef();
148}
149
150RetainPtr<CFArrayRef> BitmapImage::getCGImageArray()
151{
152    size_t count = frameCount();
153    if (!count)
154        return 0;
155
156    CFMutableArrayRef array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
157    for (size_t i = 0; i < count; ++i) {
158        if (CGImageRef currFrame = frameAtIndex(i))
159            CFArrayAppendValue(array, currFrame);
160    }
161    return adoptCF(array);
162}
163
164void BitmapImage::draw(GraphicsContext* ctx, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator op, BlendMode blendMode)
165{
166    draw(ctx, dstRect, srcRect, styleColorSpace, op, blendMode, DoNotRespectImageOrientation);
167}
168
169void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp, BlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation)
170{
171    startAnimation();
172
173    CGImageRef image = frameAtIndex(m_currentFrame);
174    if (!image) // If it's too early we won't have an image yet.
175        return;
176
177    if (mayFillWithSolidColor()) {
178        fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp);
179        return;
180    }
181
182    FloatSize selfSize = currentFrameSize();
183    ImageOrientation orientation = DefaultImageOrientation;
184
185    if (shouldRespectImageOrientation == RespectImageOrientation)
186        orientation = frameOrientationAtIndex(m_currentFrame);
187
188    ctxt->drawNativeImage(image, selfSize, styleColorSpace, destRect, srcRect, compositeOp, blendMode, orientation);
189
190    if (imageObserver())
191        imageObserver()->didDraw(this);
192}
193
194}
195
196#endif // USE(CG)
197