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