Home | History | Annotate | Download | only in canvas
      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 "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 
     52 namespace WebCore {
     53 
     54 enum ColorParseResult { ParsedRGBA, ParsedCurrentColor, ParsedSystemColor, ParseFailed };
     55 
     56 static 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 
     67 RGBA32 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 
     76 bool 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 
     94 CanvasStyle::CanvasStyle(Type type, float overrideAlpha)
     95     : m_type(type)
     96     , m_overrideAlpha(overrideAlpha)
     97 {
     98 }
     99 
    100 CanvasStyle::CanvasStyle(RGBA32 rgba)
    101     : m_type(RGBA)
    102     , m_rgba(rgba)
    103 {
    104 }
    105 
    106 CanvasStyle::CanvasStyle(float grayLevel, float alpha)
    107     : m_type(RGBA)
    108     , m_rgba(makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha))
    109 {
    110 }
    111 
    112 CanvasStyle::CanvasStyle(float r, float g, float b, float a)
    113     : m_type(RGBA)
    114     , m_rgba(makeRGBA32FromFloats(r, g, b, a))
    115 {
    116 }
    117 
    118 CanvasStyle::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 
    125 CanvasStyle::CanvasStyle(PassRefPtr<CanvasGradient> gradient)
    126     : m_type(Gradient)
    127     , m_gradient(gradient)
    128 {
    129 }
    130 
    131 CanvasStyle::CanvasStyle(PassRefPtr<CanvasPattern> pattern)
    132     : m_type(ImagePattern)
    133     , m_pattern(pattern)
    134 {
    135 }
    136 
    137 PassRefPtr<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 
    155 PassRefPtr<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 
    172 PassRefPtr<CanvasStyle> CanvasStyle::createFromGradient(PassRefPtr<CanvasGradient> gradient)
    173 {
    174     if (!gradient)
    175         return 0;
    176     return adoptRef(new CanvasStyle(gradient));
    177 }
    178 PassRefPtr<CanvasStyle> CanvasStyle::createFromPattern(PassRefPtr<CanvasPattern> pattern)
    179 {
    180     if (!pattern)
    181         return 0;
    182     return adoptRef(new CanvasStyle(pattern));
    183 }
    184 
    185 bool 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 
    210 bool 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 
    218 bool 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 
    230 void 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 
    267 void 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