1/*
2 * Copyright (C) 2016 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 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 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#pragma once
27
28#include "Color.h"
29#include "IntRect.h"
30#include "IntSize.h"
31#include "NativeImage.h"
32
33#include <wtf/Vector.h>
34
35namespace WebCore {
36
37class ImageBackingStore {
38public:
39 static std::unique_ptr<ImageBackingStore> create(const IntSize& size, bool premultiplyAlpha)
40 {
41 return std::make_unique<ImageBackingStore>(size, premultiplyAlpha);
42 }
43
44 static std::unique_ptr<ImageBackingStore> create(const ImageBackingStore& other)
45 {
46 return std::make_unique<ImageBackingStore>(other);
47 }
48
49 ImageBackingStore(const IntSize& size, bool premultiplyAlpha = true)
50 : m_premultiplyAlpha(premultiplyAlpha)
51 {
52 ASSERT(!size.isEmpty());
53 setSize(size);
54 }
55
56 ImageBackingStore(const ImageBackingStore& other)
57 {
58 if (this == &other)
59 return;
60
61 m_pixels = other.m_pixels;
62 m_pixelsPtr = m_pixels.data();
63 m_size = other.m_size;
64 m_premultiplyAlpha = other.m_premultiplyAlpha;
65 }
66
67 NativeImagePtr image() const;
68
69 bool setSize(const IntSize& size)
70 {
71 if (!m_pixels.tryReserveCapacity(size.area()))
72 return false;
73
74 m_pixels.resize(size.area());
75 m_pixelsPtr = m_pixels.data();
76 m_size = size;
77 m_frameRect = IntRect(IntPoint(), m_size);
78 clear();
79 return true;
80 }
81
82 void setFrameRect(const IntRect& frameRect)
83 {
84 ASSERT(!m_size.isEmpty());
85 ASSERT(inBounds(frameRect));
86 m_frameRect = frameRect;
87 }
88
89 IntSize size() const { return m_size; }
90 IntRect frameRect() const { return m_frameRect; }
91
92 void clear()
93 {
94 memset(m_pixelsPtr, 0, m_size.area() * sizeof(RGBA32));
95 }
96
97 void clearRect(const IntRect& rect)
98 {
99 if (rect.isEmpty() || !inBounds(rect))
100 return;
101
102 size_t rectWidthInBytes = rect.width() * sizeof(RGBA32);
103 RGBA32* start = at(rect.x(), rect.y());
104 for (int i = 0; i < rect.height(); ++i) {
105 memset(start, 0, rectWidthInBytes);
106 start += m_size.width();
107 }
108 }
109
110 void repeatFirstRow(const IntRect& rect)
111 {
112 if (rect.isEmpty() || !inBounds(rect))
113 return;
114
115 size_t rectWidthInBytes = rect.width() * sizeof(RGBA32);
116 RGBA32* src = at(rect.x(), rect.y());
117 RGBA32* dest = src + m_size.width();
118 for (int i = 1; i < rect.height(); ++i) {
119 memcpy(dest, src, rectWidthInBytes);
120 dest += m_size.width();
121 }
122 }
123
124 RGBA32* at(int x, int y) const
125 {
126 return m_pixelsPtr + y * m_size.width() + x;
127 }
128
129 void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a)
130 {
131 setRGBA(at(x, y), r, g, b, a);
132 }
133
134 void setRGBA(RGBA32* dest, unsigned r, unsigned g, unsigned b, unsigned a)
135 {
136 if (m_premultiplyAlpha && !a)
137 *dest = 0;
138 else if (m_premultiplyAlpha && a < 255)
139 *dest = makePremultipliedRGBA(r, g, b, a);
140 else
141 *dest = makeRGBA(r, g, b, a);
142 }
143
144 void overRGBA(RGBA32* dest, unsigned r, unsigned g, unsigned b, unsigned a)
145 {
146 if (!a)
147 return;
148
149 if (a >= 255 || !alphaChannel(*dest)) {
150 setRGBA(dest, r, g, b, a);
151 return;
152 }
153
154 if (!m_premultiplyAlpha)
155 *dest = makePremultipliedRGBA(redChannel(*dest), greenChannel(*dest), blueChannel(*dest), alphaChannel(*dest));
156
157 unsigned d = 255 - a;
158
159 r = fastDivideBy255(r * a + redChannel(*dest) * d);
160 g = fastDivideBy255(g * a + greenChannel(*dest) * d);
161 b = fastDivideBy255(b * a + blueChannel(*dest) * d);
162 a += fastDivideBy255(d * alphaChannel(*dest));
163
164 if (m_premultiplyAlpha)
165 *dest = makeRGBA(r, g, b, a);
166 else
167 *dest = makeUnPremultipliedRGBA(r, g, b, a);
168 }
169
170 bool inBounds(const IntRect& rect) const
171 {
172 return IntRect(IntPoint(), m_size).contains(rect);
173 }
174
175 static bool isOverSize(const IntSize& size)
176 {
177 static unsigned long long MaxPixels = ((1 << 29) - 1);
178 unsigned long long pixels = static_cast<unsigned long long>(size.width()) * static_cast<unsigned long long>(size.height());
179 return pixels > MaxPixels;
180 }
181
182private:
183 Vector<RGBA32> m_pixels;
184 RGBA32* m_pixelsPtr { nullptr };
185 IntSize m_size;
186 IntRect m_frameRect; // This will always just be the entire buffer except for GIF and PNG frames
187 bool m_premultiplyAlpha { true };
188};
189
190}