Home | History | Annotate | Download | only in css
      1 /*
      2     Copyright (C) 2008 Eric Seidel <eric (at) webkit.org>
      3     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      4                   2004, 2005, 2007, 2010 Rob Buis <buis (at) kde.org>
      5     Copyright (C) 2005, 2006 Apple Computer, Inc.
      6 
      7     This library is free software; you can redistribute it and/or
      8     modify it under the terms of the GNU Library General Public
      9     License as published by the Free Software Foundation; either
     10     version 2 of the License, or (at your option) any later version.
     11 
     12     This library is distributed in the hope that it will be useful,
     13     but WITHOUT ANY WARRANTY; without even the implied warranty of
     14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15     Library General Public License for more details.
     16 
     17     You should have received a copy of the GNU Library General Public License
     18     along with this library; see the file COPYING.LIB.  If not, write to
     19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20     Boston, MA 02110-1301, USA.
     21 */
     22 
     23 #include "config.h"
     24 
     25 #if ENABLE(SVG)
     26 #include "CSSInheritedValue.h"
     27 #include "CSSInitialValue.h"
     28 #include "CSSParser.h"
     29 #include "CSSProperty.h"
     30 #include "CSSPropertyNames.h"
     31 #include "CSSQuirkPrimitiveValue.h"
     32 #include "CSSValueKeywords.h"
     33 #include "CSSValueList.h"
     34 #include "RenderTheme.h"
     35 #include "SVGPaint.h"
     36 
     37 using namespace std;
     38 
     39 namespace WebCore {
     40 
     41 bool CSSParser::parseSVGValue(int propId, bool important)
     42 {
     43     CSSParserValue* value = m_valueList->current();
     44     if (!value)
     45         return false;
     46 
     47     int id = value->id;
     48 
     49     bool valid_primitive = false;
     50     RefPtr<CSSValue> parsedValue;
     51 
     52     switch (propId) {
     53     /* The comment to the right defines all valid value of these
     54      * properties as defined in SVG 1.1, Appendix N. Property index */
     55     case CSSPropertyAlignmentBaseline:
     56     // auto | baseline | before-edge | text-before-edge | middle |
     57     // central | after-edge | text-after-edge | ideographic | alphabetic |
     58     // hanging | mathematical | inherit
     59         if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle ||
     60           (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
     61             valid_primitive = true;
     62         break;
     63 
     64     case CSSPropertyBaselineShift:
     65     // baseline | super | sub | <percentage> | <length> | inherit
     66         if (id == CSSValueBaseline || id == CSSValueSub ||
     67            id >= CSSValueSuper)
     68             valid_primitive = true;
     69         else
     70             valid_primitive = validUnit(value, FLength|FPercent, false);
     71         break;
     72 
     73     case CSSPropertyDominantBaseline:
     74     // auto | use-script | no-change | reset-size | ideographic |
     75     // alphabetic | hanging | mathematical | central | middle |
     76     // text-after-edge | text-before-edge | inherit
     77         if (id == CSSValueAuto || id == CSSValueMiddle ||
     78           (id >= CSSValueUseScript && id <= CSSValueResetSize) ||
     79           (id >= CSSValueCentral && id <= CSSValueMathematical))
     80             valid_primitive = true;
     81         break;
     82 
     83     case CSSPropertyEnableBackground:
     84     // accumulate | new [x] [y] [width] [height] | inherit
     85         if (id == CSSValueAccumulate) // TODO : new
     86             valid_primitive = true;
     87         break;
     88 
     89     case CSSPropertyMarkerStart:
     90     case CSSPropertyMarkerMid:
     91     case CSSPropertyMarkerEnd:
     92     case CSSPropertyMask:
     93         if (id == CSSValueNone)
     94             valid_primitive = true;
     95         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
     96             parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
     97             if (parsedValue)
     98                 m_valueList->next();
     99         }
    100         break;
    101 
    102     case CSSPropertyClipRule:            // nonzero | evenodd | inherit
    103     case CSSPropertyFillRule:
    104         if (id == CSSValueNonzero || id == CSSValueEvenodd)
    105             valid_primitive = true;
    106         break;
    107 
    108     case CSSPropertyStrokeMiterlimit:   // <miterlimit> | inherit
    109         valid_primitive = validUnit(value, FNumber|FNonNeg, false);
    110         break;
    111 
    112     case CSSPropertyStrokeLinejoin:   // miter | round | bevel | inherit
    113         if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
    114             valid_primitive = true;
    115         break;
    116 
    117     case CSSPropertyStrokeLinecap:    // butt | round | square | inherit
    118         if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
    119             valid_primitive = true;
    120         break;
    121 
    122     case CSSPropertyStrokeOpacity:   // <opacity-value> | inherit
    123     case CSSPropertyFillOpacity:
    124     case CSSPropertyStopOpacity:
    125     case CSSPropertyFloodOpacity:
    126         valid_primitive = (!id && validUnit(value, FNumber|FPercent, false));
    127         break;
    128 
    129     case CSSPropertyShapeRendering:
    130     // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
    131         if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
    132             id == CSSValueCrispedges || id == CSSValueGeometricprecision)
    133             valid_primitive = true;
    134         break;
    135 
    136     case CSSPropertyImageRendering:  // auto | optimizeSpeed |
    137     case CSSPropertyColorRendering:  // optimizeQuality | inherit
    138         if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
    139             id == CSSValueOptimizequality)
    140             valid_primitive = true;
    141         break;
    142 
    143     case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
    144         if (id == CSSValueAuto || id == CSSValueSrgb)
    145             valid_primitive = true;
    146         break;
    147 
    148     case CSSPropertyColorInterpolation:   // auto | sRGB | linearRGB | inherit
    149     case CSSPropertyColorInterpolationFilters:
    150         if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
    151             valid_primitive = true;
    152         break;
    153 
    154     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
    155      * correctly and allows optimization in applyRule(..)
    156      */
    157 
    158     case CSSPropertyTextAnchor:    // start | middle | end | inherit
    159         if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
    160             valid_primitive = true;
    161         break;
    162 
    163     case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
    164         if (id == CSSValueAuto) {
    165             valid_primitive = true;
    166             break;
    167         }
    168     /* fallthrough intentional */
    169     case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
    170         if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
    171             parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
    172 
    173             if (parsedValue)
    174                 m_valueList->next();
    175         }
    176         break;
    177 
    178     case CSSPropertyFill:                 // <paint> | inherit
    179     case CSSPropertyStroke:               // <paint> | inherit
    180         {
    181             if (id == CSSValueNone)
    182                 parsedValue = SVGPaint::createNone();
    183             else if (id == CSSValueCurrentcolor)
    184                 parsedValue = SVGPaint::createCurrentColor();
    185             else if ((id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu)
    186                 parsedValue = SVGPaint::createColor(RenderTheme::defaultTheme()->systemColor(id));
    187             else if (value->unit == CSSPrimitiveValue::CSS_URI) {
    188                 RGBA32 c = Color::transparent;
    189                 if (m_valueList->next() && parseColorFromValue(m_valueList->current(), c)) {
    190                     parsedValue = SVGPaint::createURIAndColor(value->string, c);
    191                 } else
    192                     parsedValue = SVGPaint::createURI(value->string);
    193             } else
    194                 parsedValue = parseSVGPaint();
    195 
    196             if (parsedValue)
    197                 m_valueList->next();
    198         }
    199         break;
    200 
    201     case CSSPropertyColor:                // <color> | inherit
    202         if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
    203            (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
    204             parsedValue = SVGColor::createFromString(value->string);
    205         else
    206             parsedValue = parseSVGColor();
    207 
    208         if (parsedValue)
    209             m_valueList->next();
    210         break;
    211 
    212     case CSSPropertyStopColor: // TODO : icccolor
    213     case CSSPropertyFloodColor:
    214     case CSSPropertyLightingColor:
    215         if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
    216            (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
    217             parsedValue = SVGColor::createFromString(value->string);
    218         else if (id == CSSValueCurrentcolor)
    219             parsedValue = SVGColor::createCurrentColor();
    220         else // TODO : svgcolor (iccColor)
    221             parsedValue = parseSVGColor();
    222 
    223         if (parsedValue)
    224             m_valueList->next();
    225 
    226         break;
    227 
    228     case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
    229         if (id == CSSValueNone || id == CSSValueNonScalingStroke)
    230             valid_primitive = true;
    231         break;
    232 
    233     case CSSPropertyWritingMode:
    234     // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
    235         if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
    236             valid_primitive = true;
    237         break;
    238 
    239     case CSSPropertyStrokeWidth:         // <length> | inherit
    240     case CSSPropertyStrokeDashoffset:
    241         valid_primitive = validUnit(value, FLength | FPercent, false);
    242         break;
    243     case CSSPropertyStrokeDasharray:     // none | <dasharray> | inherit
    244         if (id == CSSValueNone)
    245             valid_primitive = true;
    246         else
    247             parsedValue = parseSVGStrokeDasharray();
    248 
    249         break;
    250 
    251     case CSSPropertyKerning:              // auto | normal | <length> | inherit
    252         if (id == CSSValueAuto || id == CSSValueNormal)
    253             valid_primitive = true;
    254         else
    255             valid_primitive = validUnit(value, FLength, false);
    256         break;
    257 
    258     case CSSPropertyClipPath:    // <uri> | none | inherit
    259     case CSSPropertyFilter:
    260         if (id == CSSValueNone)
    261             valid_primitive = true;
    262         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
    263             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
    264             if (parsedValue)
    265                 m_valueList->next();
    266         }
    267         break;
    268     case CSSPropertyWebkitSvgShadow:
    269         if (id == CSSValueNone)
    270             valid_primitive = true;
    271         else
    272             return parseShadow(propId, important);
    273 
    274     /* shorthand properties */
    275     case CSSPropertyMarker:
    276     {
    277         ShorthandScope scope(this, propId);
    278         m_implicitShorthand = true;
    279         if (!parseValue(CSSPropertyMarkerStart, important))
    280             return false;
    281         if (m_valueList->current()) {
    282             rollbackLastProperties(1);
    283             return false;
    284         }
    285         CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
    286         addProperty(CSSPropertyMarkerMid, value, important);
    287         addProperty(CSSPropertyMarkerEnd, value, important);
    288         m_implicitShorthand = false;
    289         return true;
    290     }
    291     default:
    292         // If you crash here, it's because you added a css property and are not handling it
    293         // in either this switch statement or the one in CSSParser::parseValue
    294         ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
    295         return false;
    296     }
    297 
    298     if (valid_primitive) {
    299         if (id != 0)
    300             parsedValue = CSSPrimitiveValue::createIdentifier(id);
    301         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
    302             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
    303         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
    304             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
    305         else if (value->unit >= CSSParserValue::Q_EMS)
    306             parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
    307         m_valueList->next();
    308     }
    309     if (!parsedValue || (m_valueList->current() && !inShorthand()))
    310         return false;
    311 
    312     addProperty(propId, parsedValue.release(), important);
    313     return true;
    314 }
    315 
    316 PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray()
    317 {
    318     RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
    319     CSSParserValue* value = m_valueList->current();
    320     bool valid_primitive = true;
    321     while (value) {
    322         valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false);
    323         if (!valid_primitive)
    324             break;
    325         if (value->id != 0)
    326             ret->append(CSSPrimitiveValue::createIdentifier(value->id));
    327         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
    328             ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
    329         value = m_valueList->next();
    330         if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
    331             value = m_valueList->next();
    332     }
    333     if (!valid_primitive)
    334         return 0;
    335     return ret.release();
    336 }
    337 
    338 PassRefPtr<CSSValue> CSSParser::parseSVGPaint()
    339 {
    340     RGBA32 c = Color::transparent;
    341     if (!parseColorFromValue(m_valueList->current(), c))
    342         return SVGPaint::createUnknown();
    343     return SVGPaint::createColor(Color(c));
    344 }
    345 
    346 PassRefPtr<CSSValue> CSSParser::parseSVGColor()
    347 {
    348     RGBA32 c = Color::transparent;
    349     if (!parseColorFromValue(m_valueList->current(), c))
    350         return 0;
    351     return SVGColor::createFromColor(Color(c));
    352 }
    353 
    354 }
    355 
    356 #endif // ENABLE(SVG)
    357