Extended Color: ColorMatrix should support smaller matrices and be constexpr
[WebKit-https.git] / Source / WebCore / platform / graphics / ColorMatrix.h
1 /*
2  * Copyright (C) 2020 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  *
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 AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "ColorComponents.h"
29 #include <math.h>
30 #include <wtf/MathExtras.h>
31
32 namespace WebCore {
33
34 template<size_t Columns, size_t Rows>
35 class ColorMatrix {
36 public:
37     template<typename ...Ts>
38     explicit constexpr ColorMatrix(Ts ...input)
39         : m_matrix {{ input ... }}
40     {
41         static_assert(sizeof...(Ts) == Rows * Columns);
42     }
43
44     constexpr void transformColorComponents(ColorComponents<float>&) const;
45     constexpr ColorComponents<float> transformedColorComponents(const ColorComponents<float>&) const;
46
47     constexpr float at(size_t row, size_t column) const
48     {
49         return m_matrix[(row * Columns) + column];
50     }
51
52 private:
53     std::array<float, Rows * Columns> m_matrix;
54 };
55
56 // FIXME: These are only used in FilterOperations.cpp. Consider moving them there.
57 constexpr ColorMatrix<3, 3> grayscaleColorMatrix(float amount)
58 {
59     // Values from https://www.w3.org/TR/filter-effects-1/#grayscaleEquivalent
60     float oneMinusAmount = std::clamp(1.0f - amount, 0.0f, 1.0f);
61     return ColorMatrix<3, 3> {
62         0.2126f + 0.7874f * oneMinusAmount, 0.7152f - 0.7152f * oneMinusAmount, 0.0722f - 0.0722f * oneMinusAmount,
63         0.2126f - 0.2126f * oneMinusAmount, 0.7152f + 0.2848f * oneMinusAmount, 0.0722f - 0.0722f * oneMinusAmount,
64         0.2126f - 0.2126f * oneMinusAmount, 0.7152f - 0.7152f * oneMinusAmount, 0.0722f + 0.9278f * oneMinusAmount
65     };
66 }
67
68 constexpr ColorMatrix<3, 3> sepiaColorMatrix(float amount)
69 {
70     // Values from https://www.w3.org/TR/filter-effects-1/#sepiaEquivalent
71     float oneMinusAmount = std::clamp(1.0f - amount, 0.0f, 1.0f);
72     return ColorMatrix<3, 3> {
73         0.393f + 0.607f * oneMinusAmount, 0.769f - 0.769f * oneMinusAmount, 0.189f - 0.189f * oneMinusAmount,
74         0.349f - 0.349f * oneMinusAmount, 0.686f + 0.314f * oneMinusAmount, 0.168f - 0.168f * oneMinusAmount,
75         0.272f - 0.272f * oneMinusAmount, 0.534f - 0.534f * oneMinusAmount, 0.131f + 0.869f * oneMinusAmount
76     };
77 }
78
79 constexpr ColorMatrix<3, 3> saturationColorMatrix(float amount)
80 {
81     // Values from https://www.w3.org/TR/filter-effects-1/#feColorMatrixElement
82     return ColorMatrix<3, 3> {
83         0.213f + 0.787f * amount,  0.715f - 0.715f * amount, 0.072f - 0.072f * amount,
84         0.213f - 0.213f * amount,  0.715f + 0.285f * amount, 0.072f - 0.072f * amount,
85         0.213f - 0.213f * amount,  0.715f - 0.715f * amount, 0.072f + 0.928f * amount
86     };
87 }
88
89 // NOTE: hueRotateColorMatrix is not constexpr due to use of cos/sin which are not constexpr yet.
90 inline ColorMatrix<3, 3> hueRotateColorMatrix(float angleInDegrees)
91 {
92     float cosHue = cos(deg2rad(angleInDegrees));
93     float sinHue = sin(deg2rad(angleInDegrees));
94
95     // Values from https://www.w3.org/TR/filter-effects-1/#feColorMatrixElement
96     return ColorMatrix<3, 3> {
97         0.213f + cosHue * 0.787f - sinHue * 0.213f, 0.715f - cosHue * 0.715f - sinHue * 0.715f, 0.072f - cosHue * 0.072f + sinHue * 0.928f,
98         0.213f - cosHue * 0.213f + sinHue * 0.143f, 0.715f + cosHue * 0.285f + sinHue * 0.140f, 0.072f - cosHue * 0.072f - sinHue * 0.283f,
99         0.213f - cosHue * 0.213f - sinHue * 0.787f, 0.715f - cosHue * 0.715f + sinHue * 0.715f, 0.072f + cosHue * 0.928f + sinHue * 0.072f
100     };
101 }
102
103 template<size_t Columns, size_t Rows>
104 constexpr void ColorMatrix<Columns, Rows>::transformColorComponents(ColorComponents<float>& inputVector) const
105 {
106     inputVector = transformedColorComponents(inputVector);
107 }
108
109 template<size_t Columns, size_t Rows>
110 constexpr ColorComponents<float> ColorMatrix<Columns, Rows>::transformedColorComponents(const ColorComponents<float>& inputVector) const
111 {
112     static_assert(ColorComponents<float>::Size >= Rows);
113     
114     ColorComponents<float> result;
115     for (size_t row = 0; row < Rows; ++row) {
116         if constexpr (Columns <= ColorComponents<float>::Size) {
117             for (size_t column = 0; column < Columns; ++column)
118                 result.components[row] += at(row, column) * inputVector.components[column];
119         } else if constexpr (Columns > ColorComponents<float>::Size) {
120             for (size_t column = 0; column < ColorComponents<float>::Size; ++column)
121                 result.components[row] += at(row, column) * inputVector.components[column];
122             for (size_t additionalColumn = ColorComponents<float>::Size; additionalColumn < Columns; ++additionalColumn)
123                 result.components[row] += at(row, additionalColumn);
124         }
125     }
126     if constexpr (ColorComponents<float>::Size > Rows) {
127         for (size_t additionalRow = Rows; additionalRow < ColorComponents<float>::Size; ++additionalRow)
128             result.components[additionalRow] = inputVector.components[additionalRow];
129     }
130
131     return result;
132 }
133
134 } // namespace WebCore