ff49ad108defd88d6f7388246d181c000b67837d
[WebKit-https.git] / Source / WebCore / html / canvas / CanvasStyle.cpp
1 /*
2  * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
4  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5  * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
27  */
28
29 #include "config.h"
30 #include "CanvasStyle.h"
31
32 #include "CSSParser.h"
33 #include "CSSPropertyNames.h"
34 #include "CanvasGradient.h"
35 #include "CanvasPattern.h"
36 #include "GraphicsContext.h"
37 #include "HTMLCanvasElement.h"
38 #include "StyleProperties.h"
39
40 #if USE(CG)
41 #include <CoreGraphics/CGContext.h>
42 #endif
43
44 namespace WebCore {
45
46 static bool isCurrentColorString(const String& colorString)
47 {
48     return equalLettersIgnoringASCIICase(colorString, "currentcolor");
49 }
50
51 static Color parseColor(const String& colorString)
52 {
53     Color color = CSSParser::parseColor(colorString);
54     if (color.isValid())
55         return color;
56     return CSSParser::parseSystemColor(colorString, std::nullopt);
57 }
58
59 Color currentColor(HTMLCanvasElement* canvas)
60 {
61     if (!canvas || !canvas->isConnected() || !canvas->inlineStyle())
62         return Color::black;
63     Color color = CSSParser::parseColor(canvas->inlineStyle()->getPropertyValue(CSSPropertyColor));
64     if (!color.isValid())
65         return Color::black;
66     return color;
67 }
68
69 Color parseColorOrCurrentColor(const String& colorString, HTMLCanvasElement* canvas)
70 {
71     if (isCurrentColorString(colorString))
72         return currentColor(canvas);
73
74     return parseColor(colorString);
75 }
76
77 CanvasStyle::CanvasStyle(Color color)
78     : m_style(color)
79 {
80 }
81
82 CanvasStyle::CanvasStyle(float grayLevel, float alpha)
83     : m_style(Color { grayLevel, grayLevel, grayLevel, alpha })
84 {
85 }
86
87 CanvasStyle::CanvasStyle(float r, float g, float b, float a)
88     : m_style(Color { r, g, b, a })
89 {
90 }
91
92 CanvasStyle::CanvasStyle(float c, float m, float y, float k, float a)
93     : m_style(CMYKAColor { Color { c, m, y, k, a }, c, m, y, k, a })
94 {
95 }
96
97 CanvasStyle::CanvasStyle(CanvasGradient& gradient)
98     : m_style(makeRefPtr(gradient))
99 {
100 }
101
102 CanvasStyle::CanvasStyle(CanvasPattern& pattern)
103     : m_style(makeRefPtr(pattern))
104 {
105 }
106
107 inline CanvasStyle::CanvasStyle(CurrentColor color)
108     : m_style(color)
109 {
110 }
111
112 CanvasStyle CanvasStyle::createFromString(const String& colorString)
113 {
114     if (isCurrentColorString(colorString))
115         return CurrentColor { std::nullopt };
116
117     Color color = parseColor(colorString);
118     if (!color.isValid())
119         return { };
120
121     return color;
122 }
123
124 CanvasStyle CanvasStyle::createFromStringWithOverrideAlpha(const String& colorString, float alpha)
125 {
126     if (isCurrentColorString(colorString))
127         return CurrentColor { alpha };
128
129     Color color = parseColor(colorString);
130     if (!color.isValid())
131         return { };
132
133     return Color { colorWithOverrideAlpha(color.rgb(), alpha) };
134 }
135
136 bool CanvasStyle::isEquivalentColor(const CanvasStyle& other) const
137 {
138     if (WTF::holds_alternative<Color>(m_style) && WTF::holds_alternative<Color>(other.m_style))
139         return WTF::get<Color>(m_style) == WTF::get<Color>(other.m_style);
140
141     if (WTF::holds_alternative<CMYKAColor>(m_style) && WTF::holds_alternative<CMYKAColor>(other.m_style)) {
142         auto& a = WTF::get<CMYKAColor>(m_style);
143         auto& b = WTF::get<CMYKAColor>(other.m_style);
144         return a.c == b.c && a.m == b.m && a.y == b.y && a.k == b.k && a.a == b.a;
145     }
146
147     return false;
148 }
149
150 bool CanvasStyle::isEquivalentRGBA(float r, float g, float b, float a) const
151 {
152     return WTF::holds_alternative<Color>(m_style) && WTF::get<Color>(m_style) == Color { r, g, b, a };
153 }
154
155 bool CanvasStyle::isEquivalentCMYKA(float c, float m, float y, float k, float a) const
156 {
157     if (!WTF::holds_alternative<CMYKAColor>(m_style))
158         return false;
159
160     auto& channels = WTF::get<CMYKAColor>(m_style);
161     return c == channels.c && m == channels.m && y == channels.y && k == channels.k && a == channels.a;
162 }
163
164 void CanvasStyle::applyStrokeColor(GraphicsContext& context) const
165 {
166     WTF::switchOn(m_style,
167         [&context] (const Color& color) {
168             context.setStrokeColor(color);
169         },
170         [&context] (const CMYKAColor& color) {
171             // FIXME: Do this through platform-independent GraphicsContext API.
172             // We'll need a fancier Color abstraction to support CMYKA correctly
173 #if USE(CG)
174             CGContextSetCMYKStrokeColor(context.platformContext(), color.c, color.m, color.y, color.k, color.a);
175 #else
176             context.setStrokeColor(color.color);
177 #endif
178         },
179         [&context] (const RefPtr<CanvasGradient>& gradient) {
180             context.setStrokeGradient(gradient->gradient());
181         },
182         [&context] (const RefPtr<CanvasPattern>& pattern) {
183             context.setStrokePattern(pattern->pattern());
184         },
185         [] (const CurrentColor&) {
186             ASSERT_NOT_REACHED();
187         },
188         [] (const Invalid&) {
189             ASSERT_NOT_REACHED();
190         }
191     );
192 }
193
194 void CanvasStyle::applyFillColor(GraphicsContext& context) const
195 {
196     WTF::switchOn(m_style,
197         [&context] (const Color& color) {
198             context.setFillColor(color);
199         },
200         [&context] (const CMYKAColor& color) {
201             // FIXME: Do this through platform-independent GraphicsContext API.
202             // We'll need a fancier Color abstraction to support CMYKA correctly
203 #if USE(CG)
204             CGContextSetCMYKFillColor(context.platformContext(), color.c, color.m, color.y, color.k, color.a);
205 #else
206             context.setFillColor(color.color);
207 #endif
208         },
209         [&context] (const RefPtr<CanvasGradient>& gradient) {
210             context.setFillGradient(gradient->gradient());
211         },
212         [&context] (const RefPtr<CanvasPattern>& pattern) {
213             context.setFillPattern(pattern->pattern());
214         },
215         [] (const CurrentColor&) {
216             ASSERT_NOT_REACHED();
217         },
218         [] (const Invalid&) {
219             ASSERT_NOT_REACHED();
220         }
221     );
222 }
223
224 }