[GTK] Implement ImageBuffer::toBGRAData
[WebKit-https.git] / Source / WebCore / platform / graphics / ImageBuffer.cpp
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-2017 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)
42 {
43     bool success = false;
44     std::unique_ptr<ImageBuffer> buffer(new ImageBuffer(size, resolutionScale, colorSpace, renderingMode, 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)
52 {
53     bool success = false;
54     std::unique_ptr<ImageBuffer> buffer(new ImageBuffer(size, resolutionScale, colorSpace, renderingMode, 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) && !PLATFORM(GTK)
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::createCompatibleBuffer(const FloatSize& size, ColorSpace colorSpace, const GraphicsContext& context)
198 {
199     if (size.isEmpty())
200         return nullptr;
201
202     IntSize scaledSize = ImageBuffer::compatibleBufferSize(size, context);
203
204     auto buffer = ImageBuffer::createCompatibleBuffer(scaledSize, 1, colorSpace, context);
205     if (!buffer)
206         return nullptr;
207
208     // Set up a corresponding scale factor on the graphics context.
209     buffer->context().scale(scaledSize / size);
210     return buffer;
211 }
212
213 std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, float resolutionScale, ColorSpace colorSpace, const GraphicsContext& context)
214 {
215     return create(size, context.renderingMode(), resolutionScale, colorSpace);
216 }
217
218 IntSize ImageBuffer::compatibleBufferSize(const FloatSize& size, const GraphicsContext& context)
219 {
220     // Enlarge the buffer size if the context's transform is scaling it so we need a higher
221     // resolution than one pixel per unit.
222     return expandedIntSize(size * context.scaleFactor());
223 }
224
225 bool ImageBuffer::isCompatibleWithContext(const GraphicsContext& context) const
226 {
227     return areEssentiallyEqual(context.scaleFactor(), this->context().scaleFactor());
228 }
229
230 #if !USE(IOSURFACE_CANVAS_BACKING_STORE)
231 size_t ImageBuffer::memoryCost() const
232 {
233     // memoryCost() may be invoked concurrently from a GC thread, and we need to be careful about what data we access here and how.
234     // It's safe to access internalSize() because it doesn't do any pointer chasing.
235     return 4 * internalSize().width() * internalSize().height();
236 }
237
238 size_t ImageBuffer::externalMemoryCost() const
239 {
240     return 0;
241 }
242 #endif
243
244 }