Use NeverDestroyed instead of DEPRECATED_DEFINE_STATIC_LOCAL
[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  *
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 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 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 #include "config.h"
28 #include "ImageBuffer.h"
29
30 #include "GraphicsContext.h"
31 #include "IntRect.h"
32 #include <wtf/MathExtras.h>
33 #include <wtf/NeverDestroyed.h>
34
35 namespace WebCore {
36
37 static const float MaxClampedLength = 4096;
38 static const float MaxClampedArea = MaxClampedLength * MaxClampedLength;
39
40 bool ImageBuffer::sizeNeedsClamping(const FloatSize& size)
41 {
42     if (size.isEmpty())
43         return false;
44
45     return floorf(size.height()) * floorf(size.width()) > MaxClampedArea;
46 }
47
48 bool ImageBuffer::sizeNeedsClamping(const FloatSize& size, FloatSize& scale)
49 {
50     FloatSize scaledSize(size);
51     scaledSize.scale(scale.width(), scale.height());
52
53     if (!sizeNeedsClamping(scaledSize))
54         return false;
55
56     // The area of scaled size is bigger than the upper limit, adjust the scale to fit.
57     scale.scale(sqrtf(MaxClampedArea / (scaledSize.width() * scaledSize.height())));
58     ASSERT(!sizeNeedsClamping(size, scale));
59     return true;
60 }
61
62 FloatSize ImageBuffer::clampedSize(const FloatSize& size)
63 {
64     return size.shrunkTo(FloatSize(MaxClampedLength, MaxClampedLength));
65 }
66
67 FloatSize ImageBuffer::clampedSize(const FloatSize& size, FloatSize& scale)
68 {
69     if (size.isEmpty())
70         return size;
71
72     FloatSize clampedSize = ImageBuffer::clampedSize(size);
73     scale = FloatSize(clampedSize.width() / size.width(), clampedSize.height() / size.height());
74     ASSERT(!sizeNeedsClamping(clampedSize));
75     ASSERT(!sizeNeedsClamping(size, scale));
76     return clampedSize;
77 }
78
79 FloatRect ImageBuffer::clampedRect(const FloatRect& rect)
80 {
81     return FloatRect(rect.location(), clampedSize(rect.size()));
82 }
83
84 #if !USE(CG)
85 FloatSize ImageBuffer::sizeForDestinationSize(FloatSize size) const
86 {
87     return size;
88 }
89
90 void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace)
91 {
92     static NeverDestroyed<Vector<int>> deviceRgbLUT;
93     static NeverDestroyed<Vector<int>> linearRgbLUT;
94
95     if (srcColorSpace == dstColorSpace)
96         return;
97
98     // only sRGB <-> linearRGB are supported at the moment
99     if ((srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceDeviceRGB)
100         || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceDeviceRGB))
101         return;
102
103     if (dstColorSpace == ColorSpaceLinearRGB) {
104         if (linearRgbLUT.get().isEmpty()) {
105             for (unsigned i = 0; i < 256; i++) {
106                 float color = i  / 255.0f;
107                 color = (color <= 0.04045f ? color / 12.92f : pow((color + 0.055f) / 1.055f, 2.4f));
108                 color = std::max(0.0f, color);
109                 color = std::min(1.0f, color);
110                 linearRgbLUT.get().append(static_cast<int>(round(color * 255)));
111             }
112         }
113         platformTransformColorSpace(linearRgbLUT.get());
114     } else if (dstColorSpace == ColorSpaceDeviceRGB) {
115         if (deviceRgbLUT.get().isEmpty()) {
116             for (unsigned i = 0; i < 256; i++) {
117                 float color = i / 255.0f;
118                 color = (powf(color, 1.0f / 2.4f) * 1.055f) - 0.055f;
119                 color = std::max(0.0f, color);
120                 color = std::min(1.0f, color);
121                 deviceRgbLUT.get().append(static_cast<int>(round(color * 255)));
122             }
123         }
124         platformTransformColorSpace(deviceRgbLUT.get());
125     }
126 }
127 #endif // USE(CG)
128
129 inline void ImageBuffer::genericConvertToLuminanceMask()
130 {
131     IntRect luminanceRect(IntPoint(), internalSize());
132     RefPtr<Uint8ClampedArray> srcPixelArray = getUnmultipliedImageData(luminanceRect);
133     
134     unsigned pixelArrayLength = srcPixelArray->length();
135     for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
136         unsigned char a = srcPixelArray->item(pixelOffset + 3);
137         if (!a)
138             continue;
139         unsigned char r = srcPixelArray->item(pixelOffset);
140         unsigned char g = srcPixelArray->item(pixelOffset + 1);
141         unsigned char b = srcPixelArray->item(pixelOffset + 2);
142         
143         double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0);
144         srcPixelArray->set(pixelOffset + 3, luma);
145     }
146     putByteArray(Unmultiplied, srcPixelArray.get(), luminanceRect.size(), luminanceRect, IntPoint());
147 }
148
149 void ImageBuffer::convertToLuminanceMask()
150 {
151     // Add platform specific functions with platformConvertToLuminanceMask here later.
152     genericConvertToLuminanceMask();
153 }
154
155 #if !USE(CAIRO)
156 PlatformLayer* ImageBuffer::platformLayer() const
157 {
158     return 0;
159 }
160
161 bool ImageBuffer::copyToPlatformTexture(GraphicsContext3D&, GC3Denum, Platform3DObject, GC3Denum, bool, bool)
162 {
163     return false;
164 }
165 #endif
166
167 std::unique_ptr<ImageBuffer> ImageBuffer::createCompatibleBuffer(const FloatSize& size, float resolutionScale, ColorSpace colorSpace, const GraphicsContext& context, bool)
168 {
169     return create(size, context.renderingMode(), resolutionScale, colorSpace);
170 }
171
172 }