1/*
2 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#ifndef ImageFrame_h
28#define ImageFrame_h
29
30#include "platform/PlatformExport.h"
31#include "platform/geometry/IntRect.h"
32#include "platform/graphics/skia/NativeImageSkia.h"
33#include "wtf/Assertions.h"
34#include "wtf/PassRefPtr.h"
35
36namespace WebCore {
37
38// ImageFrame represents the decoded image data.  This buffer is what all
39// decoders write a single frame into.
40class PLATFORM_EXPORT ImageFrame {
41public:
42    enum Status { FrameEmpty, FramePartial, FrameComplete };
43    enum DisposalMethod {
44        // If you change the numeric values of these, make sure you audit
45        // all users, as some users may cast raw values to/from these
46        // constants.
47        DisposeNotSpecified, // Leave frame in framebuffer
48        DisposeKeep, // Leave frame in framebuffer
49        DisposeOverwriteBgcolor, // Clear frame to fully transparent
50        DisposeOverwritePrevious // Clear frame to previous framebuffer contents
51    };
52    // Indicates how non-opaque pixels in the current frame rectangle
53    // are blended with those in the previous frame.
54    // Notes:
55    // * GIF always uses 'BlendAtopPreviousFrame'.
56    // * WebP also uses the 'BlendAtopBgcolor' option. This is useful for
57    //   cases where one wants to transform a few opaque pixels of the
58    //   previous frame into non-opaque pixels in the current frame.
59    enum AlphaBlendSource {
60        // Blend non-opaque pixels atop the corresponding pixels in the
61        // initial buffer state (i.e. any previous frame buffer after having
62        // been properly disposed).
63        BlendAtopPreviousFrame,
64
65        // Blend non-opaque pixels against fully transparent (i.e. simply
66        // overwrite the corresponding pixels).
67        BlendAtopBgcolor,
68    };
69    typedef uint32_t PixelData;
70
71    ImageFrame();
72
73    ImageFrame(const ImageFrame& other) { operator=(other); }
74
75    // For backends which refcount their data, this operator doesn't need to
76    // create a new copy of the image data, only increase the ref count.
77    ImageFrame& operator=(const ImageFrame& other);
78
79    // These do not touch other metadata, only the raw pixel data.
80    void clearPixelData();
81    void zeroFillPixelData();
82    void zeroFillFrameRect(const IntRect&);
83
84    // Makes this frame have an independent copy of the provided image's
85    // pixel data, so that modifications in one frame are not reflected in
86    // the other.  Returns whether the copy succeeded.
87    bool copyBitmapData(const ImageFrame&);
88
89    // Copies the pixel data at [(startX, startY), (endX, startY)) to the
90    // same X-coordinates on each subsequent row up to but not including
91    // endY.
92    void copyRowNTimes(int startX, int endX, int startY, int endY)
93    {
94        ASSERT(startX < width());
95        ASSERT(endX <= width());
96        ASSERT(startY < height());
97        ASSERT(endY <= height());
98        const int rowBytes = (endX - startX) * sizeof(PixelData);
99        const PixelData* const startAddr = getAddr(startX, startY);
100        for (int destY = startY + 1; destY < endY; ++destY)
101            memcpy(getAddr(startX, destY), startAddr, rowBytes);
102    }
103
104    // Allocates space for the pixel data.  Must be called before any pixels
105    // are written.  Must only be called once.  Returns whether allocation
106    // succeeded.
107    bool setSize(int newWidth, int newHeight);
108
109    // Returns a caller-owned pointer to the underlying native image data.
110    // (Actual use: This pointer will be owned by BitmapImage and freed in
111    // FrameData::clear()).
112    PassRefPtr<NativeImageSkia> asNewNativeImage() const;
113
114    bool hasAlpha() const;
115    const IntRect& originalFrameRect() const { return m_originalFrameRect; }
116    Status status() const { return m_status; }
117    unsigned duration() const { return m_duration; }
118    DisposalMethod disposalMethod() const { return m_disposalMethod; }
119    AlphaBlendSource alphaBlendSource() const { return m_alphaBlendSource; }
120    bool premultiplyAlpha() const { return m_premultiplyAlpha; }
121    SkBitmap::Allocator* allocator() const { return m_allocator; }
122    const SkBitmap& getSkBitmap() const { return m_bitmap; }
123    // Returns true if the pixels changed, but the bitmap has not yet been notified.
124    bool pixelsChanged() const { return m_pixelsChanged; }
125
126    size_t requiredPreviousFrameIndex() const
127    {
128        ASSERT(m_requiredPreviousFrameIndexValid);
129        return m_requiredPreviousFrameIndex;
130    }
131#if ASSERT_ENABLED
132    bool requiredPreviousFrameIndexValid() const { return m_requiredPreviousFrameIndexValid; }
133#endif
134    void setHasAlpha(bool alpha);
135    void setOriginalFrameRect(const IntRect& r) { m_originalFrameRect = r; }
136    void setStatus(Status);
137    void setDuration(unsigned duration) { m_duration = duration; }
138    void setDisposalMethod(DisposalMethod disposalMethod) { m_disposalMethod = disposalMethod; }
139    void setAlphaBlendSource(AlphaBlendSource alphaBlendSource) { m_alphaBlendSource = alphaBlendSource; }
140    void setPremultiplyAlpha(bool premultiplyAlpha) { m_premultiplyAlpha = premultiplyAlpha; }
141    void setMemoryAllocator(SkBitmap::Allocator* allocator) { m_allocator = allocator; }
142    void setSkBitmap(const SkBitmap& bitmap) { m_bitmap = bitmap; }
143    // The pixelsChanged flag needs to be set when the raw pixel data was directly modified
144    // (e.g. through a pointer or setRGBA). The flag is usually set after a batch of changes was made.
145    void setPixelsChanged(bool pixelsChanged) { m_pixelsChanged = pixelsChanged; }
146
147    void setRequiredPreviousFrameIndex(size_t previousFrameIndex)
148    {
149        m_requiredPreviousFrameIndex = previousFrameIndex;
150#if ASSERT_ENABLED
151        m_requiredPreviousFrameIndexValid = true;
152#endif
153    }
154
155    inline PixelData* getAddr(int x, int y)
156    {
157        return m_bitmap.getAddr32(x, y);
158    }
159
160    inline void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a)
161    {
162        setRGBA(getAddr(x, y), r, g, b, a);
163    }
164
165    inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a)
166    {
167        if (m_premultiplyAlpha)
168            setRGBAPremultiply(dest, r, g, b, a);
169        else
170            *dest = SkPackARGB32NoCheck(a, r, g, b);
171    }
172
173    static const unsigned div255 = static_cast<unsigned>(1.0 / 255 * (1 << 24)) + 1;
174
175    static inline void setRGBAPremultiply(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a)
176    {
177        if (a < 255) {
178            if (!a) {
179                *dest = 0;
180                return;
181            }
182
183            unsigned alpha = a * div255;
184            r = (r * alpha) >> 24;
185            g = (g * alpha) >> 24;
186            b = (b * alpha) >> 24;
187        }
188
189        // Call the "NoCheck" version since we may deliberately pass non-premultiplied
190        // values, and we don't want an assert.
191        *dest = SkPackARGB32NoCheck(a, r, g, b);
192    }
193
194    static inline void setRGBARaw(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a)
195    {
196        *dest = SkPackARGB32NoCheck(a, r, g, b);
197    }
198
199    // Notifies the SkBitmap if any pixels changed and resets the flag.
200    inline void notifyBitmapIfPixelsChanged()
201    {
202        if (m_pixelsChanged)
203            m_bitmap.notifyPixelsChanged();
204        m_pixelsChanged = false;
205    }
206
207private:
208    int width() const
209    {
210        return m_bitmap.width();
211    }
212
213    int height() const
214    {
215        return m_bitmap.height();
216    }
217
218    SkBitmap m_bitmap;
219    SkBitmap::Allocator* m_allocator;
220    bool m_hasAlpha;
221    // This will always just be the entire buffer except for GIF or WebP
222    // frames whose original rect was smaller than the overall image size.
223    IntRect m_originalFrameRect;
224    Status m_status;
225    unsigned m_duration;
226    DisposalMethod m_disposalMethod;
227    AlphaBlendSource m_alphaBlendSource;
228    bool m_premultiplyAlpha;
229    // True if the pixels changed, but the bitmap has not yet been notified.
230    bool m_pixelsChanged;
231
232    // The frame that must be decoded before this frame can be decoded.
233    // WTF::kNotFound if this frame doesn't require any previous frame.
234    // This is used by ImageDecoder::clearCacheExceptFrame(), and will never
235    // be read for image formats that do not have multiple frames.
236    size_t m_requiredPreviousFrameIndex;
237#if ASSERT_ENABLED
238    bool m_requiredPreviousFrameIndexValid;
239#endif
240};
241
242} // namespace WebCore
243
244#endif
245