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