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 #include "CSSPropertyNames.h"
     26 #include "CSSValueKeywords.h"
     27 #include "core/css/CSSParser.h"
     28 #include "core/css/CSSValueList.h"
     29 #include "core/rendering/RenderTheme.h"
     30 #include "core/svg/SVGPaint.h"
     31 
     32 using namespace std;
     33 
     34 namespace WebCore {
     35 
     36 static bool isSystemColor(int id)
     37 {
     38     return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
     39 }
     40 
     41 bool CSSParser::parseSVGValue(CSSPropertyID propId, bool important)
     42 {
     43     CSSParserValue* value = m_valueList->current();
     44     if (!value)
     45         return false;
     46 
     47     CSSValueID 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, SVGAttributeMode);
     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, SVGAttributeMode);
    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, SVGAttributeMode));
    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 CSSPropertyBufferedRendering: // auto | dynamic | static
    144         if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic)
    145             valid_primitive = true;
    146         break;
    147 
    148     case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
    149         if (id == CSSValueAuto || id == CSSValueSrgb)
    150             valid_primitive = true;
    151         break;
    152 
    153     case CSSPropertyColorInterpolation:   // auto | sRGB | linearRGB | inherit
    154     case CSSPropertyColorInterpolationFilters:
    155         if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
    156             valid_primitive = true;
    157         break;
    158 
    159     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
    160      * correctly and allows optimization in applyRule(..)
    161      */
    162 
    163     case CSSPropertyTextAnchor:    // start | middle | end | inherit
    164         if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
    165             valid_primitive = true;
    166         break;
    167 
    168     case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
    169         if (id == CSSValueAuto) {
    170             valid_primitive = true;
    171             break;
    172         }
    173     /* fallthrough intentional */
    174     case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
    175         if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
    176             parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
    177 
    178             if (parsedValue)
    179                 m_valueList->next();
    180         }
    181         break;
    182 
    183     case CSSPropertyFill:                 // <paint> | inherit
    184     case CSSPropertyStroke:               // <paint> | inherit
    185         {
    186             if (id == CSSValueNone)
    187                 parsedValue = SVGPaint::createNone();
    188             else if (id == CSSValueCurrentcolor)
    189                 parsedValue = SVGPaint::createCurrentColor();
    190             else if (isSystemColor(id))
    191                 parsedValue = SVGPaint::createColor(RenderTheme::defaultTheme()->systemColor(id));
    192             else if (value->unit == CSSPrimitiveValue::CSS_URI) {
    193                 RGBA32 c = Color::transparent;
    194                 if (m_valueList->next()) {
    195                     if (parseColorFromValue(m_valueList->current(), c))
    196                         parsedValue = SVGPaint::createURIAndColor(value->string, c);
    197                     else if (m_valueList->current()->id == CSSValueNone)
    198                         parsedValue = SVGPaint::createURIAndNone(value->string);
    199                 }
    200                 if (!parsedValue)
    201                     parsedValue = SVGPaint::createURI(value->string);
    202             } else
    203                 parsedValue = parseSVGPaint();
    204 
    205             if (parsedValue)
    206                 m_valueList->next();
    207         }
    208         break;
    209 
    210     case CSSPropertyStopColor: // TODO : icccolor
    211     case CSSPropertyFloodColor:
    212     case CSSPropertyLightingColor:
    213         if (isSystemColor(id))
    214             parsedValue = SVGColor::createFromColor(RenderTheme::defaultTheme()->systemColor(id));
    215         else if ((id >= CSSValueAqua && id <= CSSValueTransparent) ||
    216                 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey)
    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, SVGAttributeMode);
    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, SVGAttributeMode);
    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 CSSPropertyMaskType: // luminance | alpha | inherit
    269         if (id == CSSValueLuminance || id == CSSValueAlpha)
    270             valid_primitive = true;
    271         break;
    272 
    273     /* shorthand properties */
    274     case CSSPropertyMarker:
    275     {
    276         ShorthandScope scope(this, propId);
    277         CSSParser::ImplicitScope implicitScope(this, PropertyImplicit);
    278         if (!parseValue(CSSPropertyMarkerStart, important))
    279             return false;
    280         if (m_valueList->current()) {
    281             rollbackLastProperties(1);
    282             return false;
    283         }
    284         CSSValue* value = m_parsedProperties.last().value();
    285         addProperty(CSSPropertyMarkerMid, value, important);
    286         addProperty(CSSPropertyMarkerEnd, value, important);
    287         return true;
    288     }
    289     default:
    290         // If you crash here, it's because you added a css property and are not handling it
    291         // in either this switch statement or the one in CSSParser::parseValue
    292         ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
    293         return false;
    294     }
    295 
    296     if (valid_primitive) {
    297         if (id != 0)
    298             parsedValue = CSSPrimitiveValue::createIdentifier(id);
    299         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
    300             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
    301         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
    302             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
    303         else if (value->unit >= CSSParserValue::Q_EMS)
    304             parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
    305         if (isCalculation(value)) {
    306             // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie
    307             // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release());
    308             m_parsedCalculation.release();
    309             parsedValue = 0;
    310         }
    311         m_valueList->next();
    312     }
    313     if (!parsedValue || (m_valueList->current() && !inShorthand()))
    314         return false;
    315 
    316     addProperty(propId, parsedValue.release(), important);
    317     return true;
    318 }
    319 
    320 PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray()
    321 {
    322     RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
    323     CSSParserValue* value = m_valueList->current();
    324     bool valid_primitive = true;
    325     while (value) {
    326         valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
    327         if (!valid_primitive)
    328             break;
    329         if (value->id != 0)
    330             ret->append(CSSPrimitiveValue::createIdentifier(value->id));
    331         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
    332             ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
    333         value = m_valueList->next();
    334         if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
    335             value = m_valueList->next();
    336     }
    337     if (!valid_primitive)
    338         return 0;
    339     return ret.release();
    340 }
    341 
    342 PassRefPtr<CSSValue> CSSParser::parseSVGPaint()
    343 {
    344     RGBA32 c = Color::transparent;
    345     if (!parseColorFromValue(m_valueList->current(), c))
    346         return SVGPaint::createUnknown();
    347     return SVGPaint::createColor(Color(c));
    348 }
    349 
    350 PassRefPtr<CSSValue> CSSParser::parseSVGColor()
    351 {
    352     RGBA32 c = Color::transparent;
    353     if (!parseColorFromValue(m_valueList->current(), c))
    354         return 0;
    355     return SVGColor::createFromColor(Color(c));
    356 }
    357 
    358 }
    359