1 | /* |
2 | * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> |
3 | * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
4 | * Copyright (C) 2016-2018 Apple Inc. All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
18 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
19 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | #include "config.h" |
29 | #include "ImageBuffer.h" |
30 | |
31 | #include "ColorUtilities.h" |
32 | #include "GraphicsContext.h" |
33 | #include "IntRect.h" |
34 | #include <wtf/MathExtras.h> |
35 | |
36 | namespace WebCore { |
37 | |
38 | static const float MaxClampedLength = 4096; |
39 | static const float MaxClampedArea = MaxClampedLength * MaxClampedLength; |
40 | |
41 | std::unique_ptr<ImageBuffer> ImageBuffer::create(const FloatSize& size, RenderingMode renderingMode, float resolutionScale, ColorSpace colorSpace, const HostWindow* hostWindow) |
42 | { |
43 | bool success = false; |
44 | std::unique_ptr<ImageBuffer> buffer(new ImageBuffer(size, resolutionScale, colorSpace, renderingMode, hostWindow, success)); |
45 | if (!success) |
46 | return nullptr; |
47 | return buffer; |
48 | } |
49 | |
50 | #if USE(DIRECT2D) |
51 | std::unique_ptr<ImageBuffer> ImageBuffer::create(const FloatSize& size, RenderingMode renderingMode, const GraphicsContext* targetContext, float resolutionScale, ColorSpace colorSpace, const HostWindow* hostWindow) |
52 | { |
53 | bool success = false; |
54 | std::unique_ptr<ImageBuffer> buffer(new ImageBuffer(size, resolutionScale, colorSpace, renderingMode, hostWindow, targetContext, success)); |
55 | if (!success) |
56 | return nullptr; |
57 | return buffer; |
58 | } |
59 | #endif |
60 | |
61 | bool ImageBuffer::sizeNeedsClamping(const FloatSize& size) |
62 | { |
63 | if (size.isEmpty()) |
64 | return false; |
65 | |
66 | return floorf(size.height()) * floorf(size.width()) > MaxClampedArea; |
67 | } |
68 | |
69 | bool ImageBuffer::sizeNeedsClamping(const FloatSize& size, FloatSize& scale) |
70 | { |
71 | FloatSize scaledSize(size); |
72 | scaledSize.scale(scale.width(), scale.height()); |
73 | |
74 | if (!sizeNeedsClamping(scaledSize)) |
75 | return false; |
76 | |
77 | // The area of scaled size is bigger than the upper limit, adjust the scale to fit. |
78 | scale.scale(sqrtf(MaxClampedArea / (scaledSize.width() * scaledSize.height()))); |
79 | ASSERT(!sizeNeedsClamping(size, scale)); |
80 | return true; |
81 | } |
82 | |
83 | FloatSize ImageBuffer::clampedSize(const FloatSize& size) |
84 | { |
85 | return size.shrunkTo(FloatSize(MaxClampedLength, MaxClampedLength)); |
86 | } |
87 | |
88 | FloatSize ImageBuffer::clampedSize(const FloatSize& size, FloatSize& scale) |
89 | { |
90 | if (size.isEmpty()) |
91 | return size; |
92 | |
93 | FloatSize clampedSize = ImageBuffer::clampedSize(size); |
94 | scale = clampedSize / size; |
95 | ASSERT(!sizeNeedsClamping(clampedSize)); |
96 | ASSERT(!sizeNeedsClamping(size, scale)); |
97 | return clampedSize; |
98 | } |
99 | |
100 | FloatRect ImageBuffer::clampedRect(const FloatRect& rect) |
101 | { |
102 | return FloatRect(rect.location(), clampedSize(rect.size())); |
103 | } |
104 | |
105 | #if !USE(CG) && !USE(CAIRO) |
106 | Vector<uint8_t> ImageBuffer::toBGRAData() const |
107 | { |
108 | // FIXME: Implement this for other backends. |
109 | return { }; |
110 | } |
111 | #endif |
112 | |
113 | #if !(USE(CG) || USE(DIRECT2D)) |
114 | |
115 | FloatSize ImageBuffer::sizeForDestinationSize(FloatSize size) const |
116 | { |
117 | return size; |
118 | } |
119 | |
120 | void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace) |
121 | { |
122 | if (srcColorSpace == dstColorSpace) |
123 | return; |
124 | |
125 | // only sRGB <-> linearRGB are supported at the moment |
126 | if ((srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceSRGB) |
127 | || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceSRGB)) |
128 | return; |
129 | |
130 | if (dstColorSpace == ColorSpaceLinearRGB) { |
131 | static const std::array<uint8_t, 256> linearRgbLUT = [] { |
132 | std::array<uint8_t, 256> array; |
133 | for (unsigned i = 0; i < 256; i++) { |
134 | float color = i / 255.0f; |
135 | color = sRGBToLinearColorComponent(color); |
136 | array[i] = static_cast<uint8_t>(round(color * 255)); |
137 | } |
138 | return array; |
139 | }(); |
140 | platformTransformColorSpace(linearRgbLUT); |
141 | } else if (dstColorSpace == ColorSpaceSRGB) { |
142 | static const std::array<uint8_t, 256> deviceRgbLUT= [] { |
143 | std::array<uint8_t, 256> array; |
144 | for (unsigned i = 0; i < 256; i++) { |
145 | float color = i / 255.0f; |
146 | color = linearToSRGBColorComponent(color); |
147 | array[i] = static_cast<uint8_t>(round(color * 255)); |
148 | } |
149 | return array; |
150 | }(); |
151 | platformTransformColorSpace(deviceRgbLUT); |
152 | } |
153 | } |
154 | |
155 | #endif // USE(CG) |
156 | |
157 | inline void ImageBuffer::genericConvertToLuminanceMask() |
158 | { |
159 | IntRect luminanceRect(IntPoint(), internalSize()); |
160 | auto srcPixelArray = getUnmultipliedImageData(luminanceRect); |
161 | if (!srcPixelArray) |
162 | return; |
163 | |
164 | unsigned pixelArrayLength = srcPixelArray->length(); |
165 | for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { |
166 | uint8_t a = srcPixelArray->item(pixelOffset + 3); |
167 | if (!a) |
168 | continue; |
169 | uint8_t r = srcPixelArray->item(pixelOffset); |
170 | uint8_t g = srcPixelArray->item(pixelOffset + 1); |
171 | uint8_t b = srcPixelArray->item(pixelOffset + 2); |
172 | |
173 | double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0); |
174 | srcPixelArray->set(pixelOffset + 3, luma); |
175 | } |
176 | putByteArray(*srcPixelArray, AlphaPremultiplication::Unpremultiplied, luminanceRect.size(), luminanceRect, IntPoint()); |
177 | } |
178 | |
179 | void ImageBuffer::convertToLuminanceMask() |
180 | { |
181 | // Add platform specific functions with platformConvertToLuminanceMask here later. |
182 | genericConvertToLuminanceMask(); |
183 | } |
184 | |
185 | #if !USE(CAIRO) |
186 | PlatformLayer* ImageBuffer::platformLayer() const |
187 | { |
188 | return 0; |
189 | } |
190 | |
191 | bool ImageBuffer::copyToPlatformTexture(GraphicsContext3D&, GC3Denum, Platform3DObject, GC3Denum, bool, bool) |
192 | { |
193 | return false; |
194 | } |
195 | #endif |
196 | |
197 | std::unique_ptr<ImageBuffer> ImageBuffer::copyRectToBuffer(const FloatRect& rect, ColorSpace colorSpace, const GraphicsContext& context) |
198 | { |
199 | if (rect.isEmpty()) |
200 | return nullptr; |
201 | |
202 | IntSize scaledSize = ImageBuffer::compatibleBufferSize(rect.size(), context); |
203 | |
204 | auto buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, colorSpace, context); |
205 | if (!buffer) |
206 | return nullptr; |
207 | |
208 | buffer->context().drawImageBuffer(*this, -rect.location()); |
209 | return buffer; |
210 | } |
211 | |
212 | std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, ColorSpace colorSpace, const GraphicsContext& context) |
213 | { |
214 | if (size.isEmpty()) |
215 | return nullptr; |
216 | |
217 | IntSize scaledSize = ImageBuffer::compatibleBufferSize(size, context); |
218 | |
219 | auto buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, colorSpace, context); |
220 | if (!buffer) |
221 | return nullptr; |
222 | |
223 | // Set up a corresponding scale factor on the graphics context. |
224 | buffer->context().scale(scaledSize / size); |
225 | return buffer; |
226 | } |
227 | |
228 | std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, float resolutionScale, ColorSpace colorSpace, const GraphicsContext& context) |
229 | { |
230 | #if USE(DIRECT2D) |
231 | return create(size, context.renderingMode(), &context, resolutionScale, colorSpace); |
232 | #else |
233 | return create(size, context.renderingMode(), resolutionScale, colorSpace); |
234 | #endif |
235 | } |
236 | |
237 | IntSize ImageBuffer::compatibleBufferSize(const FloatSize& size, const GraphicsContext& context) |
238 | { |
239 | // Enlarge the buffer size if the context's transform is scaling it so we need a higher |
240 | // resolution than one pixel per unit. |
241 | return expandedIntSize(size * context.scaleFactor()); |
242 | } |
243 | |
244 | bool ImageBuffer::isCompatibleWithContext(const GraphicsContext& context) const |
245 | { |
246 | return areEssentiallyEqual(context.scaleFactor(), this->context().scaleFactor()); |
247 | } |
248 | |
249 | #if !USE(IOSURFACE_CANVAS_BACKING_STORE) |
250 | size_t ImageBuffer::memoryCost() const |
251 | { |
252 | // memoryCost() may be invoked concurrently from a GC thread, and we need to be careful about what data we access here and how. |
253 | // It's safe to access internalSize() because it doesn't do any pointer chasing. |
254 | return 4 * internalSize().width() * internalSize().height(); |
255 | } |
256 | |
257 | size_t ImageBuffer::externalMemoryCost() const |
258 | { |
259 | return 0; |
260 | } |
261 | #endif |
262 | |
263 | } |
264 | |