CanvasStyle.cpp revision 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00
1/*
2 * Copyright (C) 2006, 2008 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 COMPUTER, 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 COMPUTER, 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 <wtf/Assertions.h>
39#include <wtf/PassRefPtr.h>
40
41#if USE(CG)
42#include <CoreGraphics/CGContext.h>
43#endif
44
45#if PLATFORM(QT)
46#include <QPainter>
47#include <QBrush>
48#include <QPen>
49#include <QColor>
50#endif
51
52namespace WebCore {
53
54enum ColorParseResult { ParsedRGBA, ParsedCurrentColor, ParsedSystemColor, ParseFailed };
55
56static ColorParseResult parseColor(RGBA32& parsedColor, const String& colorString, Document* document = 0)
57{
58    if (equalIgnoringCase(colorString, "currentcolor"))
59        return ParsedCurrentColor;
60    if (CSSParser::parseColor(parsedColor, colorString))
61        return ParsedRGBA;
62    if (CSSParser::parseSystemColor(parsedColor, colorString, document))
63        return ParsedSystemColor;
64    return ParseFailed;
65}
66
67RGBA32 currentColor(HTMLCanvasElement* canvas)
68{
69    if (!canvas || !canvas->inDocument())
70        return Color::black;
71    RGBA32 rgba = Color::black;
72    CSSParser::parseColor(rgba, canvas->style()->getPropertyValue(CSSPropertyColor));
73    return rgba;
74}
75
76bool parseColorOrCurrentColor(RGBA32& parsedColor, const String& colorString, HTMLCanvasElement* canvas)
77{
78    ColorParseResult parseResult = parseColor(parsedColor, colorString, canvas ? canvas->document() : 0);
79    switch (parseResult) {
80    case ParsedRGBA:
81    case ParsedSystemColor:
82        return true;
83    case ParsedCurrentColor:
84        parsedColor = currentColor(canvas);
85        return true;
86    case ParseFailed:
87        return false;
88    default:
89        ASSERT_NOT_REACHED();
90        return false;
91    }
92}
93
94CanvasStyle::CanvasStyle(Type type, float overrideAlpha)
95    : m_type(type)
96    , m_overrideAlpha(overrideAlpha)
97{
98}
99
100CanvasStyle::CanvasStyle(RGBA32 rgba)
101    : m_type(RGBA)
102    , m_rgba(rgba)
103{
104}
105
106CanvasStyle::CanvasStyle(float grayLevel, float alpha)
107    : m_type(RGBA)
108    , m_rgba(makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha))
109{
110}
111
112CanvasStyle::CanvasStyle(float r, float g, float b, float a)
113    : m_type(RGBA)
114    , m_rgba(makeRGBA32FromFloats(r, g, b, a))
115{
116}
117
118CanvasStyle::CanvasStyle(float c, float m, float y, float k, float a)
119    : m_type(CMYKA)
120    , m_rgba(makeRGBAFromCMYKA(c, m, y, k, a))
121    , m_cmyka(c, m, y, k, a)
122{
123}
124
125CanvasStyle::CanvasStyle(PassRefPtr<CanvasGradient> gradient)
126    : m_type(Gradient)
127    , m_gradient(gradient)
128{
129}
130
131CanvasStyle::CanvasStyle(PassRefPtr<CanvasPattern> pattern)
132    : m_type(ImagePattern)
133    , m_pattern(pattern)
134{
135}
136
137PassRefPtr<CanvasStyle> CanvasStyle::createFromString(const String& color, Document* document)
138{
139    RGBA32 rgba;
140    ColorParseResult parseResult = parseColor(rgba, color, document);
141    switch (parseResult) {
142    case ParsedRGBA:
143    case ParsedSystemColor:
144        return adoptRef(new CanvasStyle(rgba));
145    case ParsedCurrentColor:
146        return adoptRef(new CanvasStyle(CurrentColor));
147    case ParseFailed:
148        return 0;
149    default:
150        ASSERT_NOT_REACHED();
151        return 0;
152    }
153}
154
155PassRefPtr<CanvasStyle> CanvasStyle::createFromStringWithOverrideAlpha(const String& color, float alpha)
156{
157    RGBA32 rgba;
158    ColorParseResult parseResult = parseColor(rgba, color);
159    switch (parseResult) {
160    case ParsedRGBA:
161        return adoptRef(new CanvasStyle(colorWithOverrideAlpha(rgba, alpha)));
162    case ParsedCurrentColor:
163        return adoptRef(new CanvasStyle(CurrentColorWithOverrideAlpha, alpha));
164    case ParseFailed:
165        return 0;
166    default:
167        ASSERT_NOT_REACHED();
168        return 0;
169    }
170}
171
172PassRefPtr<CanvasStyle> CanvasStyle::createFromGradient(PassRefPtr<CanvasGradient> gradient)
173{
174    if (!gradient)
175        return 0;
176    return adoptRef(new CanvasStyle(gradient));
177}
178PassRefPtr<CanvasStyle> CanvasStyle::createFromPattern(PassRefPtr<CanvasPattern> pattern)
179{
180    if (!pattern)
181        return 0;
182    return adoptRef(new CanvasStyle(pattern));
183}
184
185bool CanvasStyle::isEquivalentColor(const CanvasStyle& other) const
186{
187    if (m_type != other.m_type)
188        return false;
189
190    switch (m_type) {
191    case RGBA:
192        return m_rgba == other.m_rgba;
193    case CMYKA:
194        return m_cmyka.c == other.m_cmyka.c
195            && m_cmyka.m == other.m_cmyka.m
196            && m_cmyka.y == other.m_cmyka.y
197            && m_cmyka.k == other.m_cmyka.k
198            && m_cmyka.a == other.m_cmyka.a;
199    case Gradient:
200    case ImagePattern:
201    case CurrentColor:
202    case CurrentColorWithOverrideAlpha:
203        return false;
204    }
205
206    ASSERT_NOT_REACHED();
207    return false;
208}
209
210bool CanvasStyle::isEquivalentRGBA(float r, float g, float b, float a) const
211{
212    if (m_type != RGBA)
213        return false;
214
215    return m_rgba == makeRGBA32FromFloats(r, g, b, a);
216}
217
218bool CanvasStyle::isEquivalentCMYKA(float c, float m, float y, float k, float a) const
219{
220    if (m_type != CMYKA)
221        return false;
222
223    return c == m_cmyka.c
224        && m == m_cmyka.m
225        && y == m_cmyka.y
226        && k == m_cmyka.k
227        && a == m_cmyka.a;
228}
229
230void CanvasStyle::applyStrokeColor(GraphicsContext* context)
231{
232    if (!context)
233        return;
234    switch (m_type) {
235    case RGBA:
236        context->setStrokeColor(m_rgba, ColorSpaceDeviceRGB);
237        break;
238    case CMYKA: {
239        // FIXME: Do this through platform-independent GraphicsContext API.
240        // We'll need a fancier Color abstraction to support CMYKA correctly
241#if USE(CG)
242        CGContextSetCMYKStrokeColor(context->platformContext(), m_cmyka.c, m_cmyka.m, m_cmyka.y, m_cmyka.k, m_cmyka.a);
243#elif PLATFORM(QT)
244        QPen currentPen = context->platformContext()->pen();
245        QColor clr;
246        clr.setCmykF(m_cmyka.c, m_cmyka.m, m_cmyka.y, m_cmyka.k, m_cmyka.a);
247        currentPen.setColor(clr);
248        context->platformContext()->setPen(currentPen);
249#else
250        context->setStrokeColor(m_rgba, ColorSpaceDeviceRGB);
251#endif
252        break;
253    }
254    case Gradient:
255        context->setStrokeGradient(canvasGradient()->gradient());
256        break;
257    case ImagePattern:
258        context->setStrokePattern(canvasPattern()->pattern());
259        break;
260    case CurrentColor:
261    case CurrentColorWithOverrideAlpha:
262        ASSERT_NOT_REACHED();
263        break;
264    }
265}
266
267void CanvasStyle::applyFillColor(GraphicsContext* context)
268{
269    if (!context)
270        return;
271    switch (m_type) {
272    case RGBA:
273        context->setFillColor(m_rgba, ColorSpaceDeviceRGB);
274        break;
275    case CMYKA: {
276        // FIXME: Do this through platform-independent GraphicsContext API.
277        // We'll need a fancier Color abstraction to support CMYKA correctly
278#if USE(CG)
279        CGContextSetCMYKFillColor(context->platformContext(), m_cmyka.c, m_cmyka.m, m_cmyka.y, m_cmyka.k, m_cmyka.a);
280#elif PLATFORM(QT)
281        QBrush currentBrush = context->platformContext()->brush();
282        QColor clr;
283        clr.setCmykF(m_cmyka.c, m_cmyka.m, m_cmyka.y, m_cmyka.k, m_cmyka.a);
284        currentBrush.setColor(clr);
285        context->platformContext()->setBrush(currentBrush);
286#else
287        context->setFillColor(m_rgba, ColorSpaceDeviceRGB);
288#endif
289        break;
290    }
291    case Gradient:
292        context->setFillGradient(canvasGradient()->gradient());
293        break;
294    case ImagePattern:
295        context->setFillPattern(canvasPattern()->pattern());
296        break;
297    case CurrentColor:
298    case CurrentColorWithOverrideAlpha:
299        ASSERT_NOT_REACHED();
300        break;
301    }
302}
303
304}
305