File indexing completed on 2024-04-28 15:22:41

0001 /*
0002     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
0003                   2004, 2005, 2007 Rob Buis <buis@kde.org>
0004     Copyright (C) 2005, 2006 Apple Computer, Inc.
0005 
0006     This file is part of the KDE project
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Library General Public
0010     License as published by the Free Software Foundation; either
0011     version 2 of the License, or (at your option) any later version.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Library General Public License for more details.
0017 
0018     You should have received a copy of the GNU Library General Public License
0019     along with this library; see the file COPYING.LIB.  If not, write to
0020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021     Boston, MA 02110-1301, USA.
0022 */
0023 
0024 #include "cssparser.h"
0025 #include "cssproperties.h"
0026 #include "cssvalues.h"
0027 
0028 #include "css/css_valueimpl.h"
0029 #include "css/css_svgvalueimpl.h"
0030 
0031 using namespace std;
0032 
0033 namespace DOM
0034 {
0035 
0036 bool CSSParser::parseSVGValue(int propId, bool important)
0037 {
0038     Value *value = valueList->current();
0039     if (!value) {
0040         return false;
0041     }
0042 
0043     int id = value->id;
0044 
0045     bool valid_primitive = false;
0046     CSSValueImpl *parsedValue = nullptr;
0047 
0048     switch (propId) {
0049     /* The comment to the right defines all valid value of these
0050      * properties as defined in SVG 1.1, Appendix N. Property index */
0051     case CSS_PROP_ALIGNMENT_BASELINE:
0052         // auto | baseline | before-edge | text-before-edge | middle |
0053         // central | after-edge | text-after-edge | ideographic | alphabetic |
0054         // hanging | mathematical | inherit
0055         if (id == CSS_VAL_AUTO || id == CSS_VAL_BASELINE || id == CSS_VAL_MIDDLE ||
0056                 (id >= CSS_VAL_BEFORE_EDGE && id <= CSS_VAL_MATHEMATICAL)) {
0057             valid_primitive = true;
0058         }
0059         break;
0060 
0061     case CSS_PROP_BASELINE_SHIFT:
0062         // baseline | super | sub | <percentage> | <length> | inherit
0063         if (id == CSS_VAL_BASELINE || id == CSS_VAL_SUB || id >= CSS_VAL_SUPER) {
0064             valid_primitive = true;
0065         } else {
0066             valid_primitive = validUnit(value, FLength | FPercent, false);
0067         }
0068         break;
0069 
0070     case CSS_PROP_DOMINANT_BASELINE:
0071         // auto | use-script | no-change | reset-size | ideographic |
0072         // alphabetic | hanging | mathematical | central | middle |
0073         // text-after-edge | text-before-edge | inherit
0074         if (id == CSS_VAL_AUTO || id == CSS_VAL_MIDDLE ||
0075                 (id >= CSS_VAL_USE_SCRIPT && id <= CSS_VAL_RESET_SIZE) ||
0076                 (id >= CSS_VAL_CENTRAL && id <= CSS_VAL_MATHEMATICAL)) {
0077             valid_primitive = true;
0078         }
0079         break;
0080 
0081     case CSS_PROP_ENABLE_BACKGROUND:
0082         // accumulate | new [x] [y] [width] [height] | inherit
0083         if (id == CSS_VAL_ACCUMULATE) { // ### TODO: new
0084             valid_primitive = true;
0085         }
0086         break;
0087 
0088     case CSS_PROP_MARKER_START:
0089     case CSS_PROP_MARKER_MID:
0090     case CSS_PROP_MARKER_END:
0091     case CSS_PROP_MASK:
0092         if (id == CSS_VAL_NONE) {
0093             valid_primitive = true;
0094         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
0095             parsedValue = new CSSPrimitiveValueImpl(domString(value->string), CSSPrimitiveValue::CSS_URI);
0096             if (parsedValue) {
0097                 valueList->next();
0098             }
0099         }
0100         break;
0101 
0102     case CSS_PROP_CLIP_RULE:            // nonzero | evenodd | inherit
0103     case CSS_PROP_FILL_RULE:
0104         if (id == CSS_VAL_NONZERO || id == CSS_VAL_EVENODD) {
0105             valid_primitive = true;
0106         }
0107         break;
0108 
0109     case CSS_PROP_STROKE_MITERLIMIT:   // <miterlimit> | inherit
0110         valid_primitive = validUnit(value, FNumber | FNonNeg, false);
0111         break;
0112 
0113     case CSS_PROP_STROKE_LINEJOIN:   // miter | round | bevel | inherit
0114         if (id == CSS_VAL_MITER || id == CSS_VAL_ROUND || id == CSS_VAL_BEVEL) {
0115             valid_primitive = true;
0116         }
0117         break;
0118 
0119     case CSS_PROP_STROKE_LINECAP:    // butt | round | square | inherit
0120         if (id == CSS_VAL_BUTT || id == CSS_VAL_ROUND || id == CSS_VAL_SQUARE) {
0121             valid_primitive = true;
0122         }
0123         break;
0124 
0125     case CSS_PROP_STROKE_OPACITY:   // <opacity-value> | inherit
0126     case CSS_PROP_FILL_OPACITY:
0127     case CSS_PROP_STOP_OPACITY:
0128     case CSS_PROP_FLOOD_OPACITY:
0129         valid_primitive = (!id && validUnit(value, FNumber | FPercent, false));
0130         break;
0131 
0132     case CSS_PROP_SHAPE_RENDERING:
0133         // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
0134         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED ||
0135                 id == CSS_VAL_CRISPEDGES || id == CSS_VAL_GEOMETRICPRECISION) {
0136             valid_primitive = true;
0137         }
0138         break;
0139 
0140     case CSS_PROP_TEXT_RENDERING:   // auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit
0141         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED || id == CSS_VAL_OPTIMIZELEGIBILITY ||
0142                 id == CSS_VAL_GEOMETRICPRECISION) {
0143             valid_primitive = true;
0144         }
0145         break;
0146 
0147     case CSS_PROP_IMAGE_RENDERING:  // auto | optimizeSpeed |
0148     case CSS_PROP_COLOR_RENDERING:  // optimizeQuality | inherit
0149         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED ||
0150                 id == CSS_VAL_OPTIMIZEQUALITY) {
0151             valid_primitive = true;
0152         }
0153         break;
0154 
0155     case CSS_PROP_COLOR_PROFILE: // auto | sRGB | <name> | <uri> inherit
0156         if (id == CSS_VAL_AUTO || id == CSS_VAL_SRGB) {
0157             valid_primitive = true;
0158         }
0159         break;
0160 
0161     case CSS_PROP_COLOR_INTERPOLATION:   // auto | sRGB | linearRGB | inherit
0162     case CSS_PROP_COLOR_INTERPOLATION_FILTERS:
0163         if (id == CSS_VAL_AUTO || id == CSS_VAL_SRGB || id == CSS_VAL_LINEARRGB) {
0164             valid_primitive = true;
0165         }
0166         break;
0167 
0168     case CSS_PROP_POINTER_EVENTS:
0169         // visiblePainted | visibleFill | visibleStroke | visible |
0170         // painted | fill | stroke | all | none |  inherit
0171         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_NONE ||
0172                 (id >= CSS_VAL_VISIBLEPAINTED && id <= CSS_VAL_ALL)) {
0173             valid_primitive = true;
0174         }
0175         break;
0176 
0177     case CSS_PROP_TEXT_ANCHOR:    // start | middle | end | inherit
0178         if (id == CSS_VAL_START || id == CSS_VAL_MIDDLE || id == CSS_VAL_END) {
0179             valid_primitive = true;
0180         }
0181         break;
0182 
0183     case CSS_PROP_GLYPH_ORIENTATION_VERTICAL: // auto | <angle> | inherit
0184         if (id == CSS_VAL_AUTO) {
0185             valid_primitive = true;
0186             break;
0187         }
0188     /* fallthrough intentional */
0189     case CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
0190         if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
0191             parsedValue = new CSSPrimitiveValueImpl(value->fValue, CSSPrimitiveValue::CSS_DEG);
0192 
0193             if (parsedValue) {
0194                 valueList->next();
0195             }
0196         }
0197         break;
0198 
0199     case CSS_PROP_FILL:                 // <paint> | inherit
0200     case CSS_PROP_STROKE: {             // <paint> | inherit
0201         if (id == CSS_VAL_NONE) {
0202             parsedValue = new SVGPaintImpl(SVGPaintImpl::SVG_PAINTTYPE_NONE);
0203         } else if (id == CSS_VAL_CURRENTCOLOR) {
0204             parsedValue = new SVGPaintImpl(SVGPaintImpl::SVG_PAINTTYPE_CURRENTCOLOR);
0205         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
0206             CSSPrimitiveValueImpl *val;
0207             if (valueList->next() && (val = parseColorFromValue(valueList->current()/*, c, true*/))) {
0208                 parsedValue = new SVGPaintImpl(domString(value->string), val->getRGBColorValue());
0209                 delete val;
0210             } else {
0211                 parsedValue = new SVGPaintImpl(SVGPaintImpl::SVG_PAINTTYPE_URI, domString(value->string));
0212             }
0213         } else {
0214             parsedValue = parseSVGPaint();
0215         }
0216 
0217         if (parsedValue) {
0218             valueList->next();
0219         }
0220     }
0221     break;
0222 
0223     /*case CSS_PROP_Color:                // <color> | inherit
0224         if ((id >= CSS_VAL_Aqua && id <= CSS_VAL_Windowtext) ||
0225            (id >= CSS_VAL_Aliceblue && id <= CSS_VAL_Yellowgreen))
0226             parsedValue = new SVGColor(value->string);
0227         else
0228             parsedValue = parseSVGColor();
0229 
0230         if (parsedValue)
0231             valueList->next();
0232         break;*/
0233 
0234     case CSS_PROP_STOP_COLOR: // TODO : icccolor
0235     case CSS_PROP_FLOOD_COLOR:
0236     case CSS_PROP_LIGHTING_COLOR:
0237         if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT)/* ||
0238            (id >= CSS_VAL_Aliceblue && id <= CSS_VAL_Yellowgreen)*/) {
0239             parsedValue = new SVGColorImpl(domString(value->string));
0240         } else if (id == CSS_VAL_CURRENTCOLOR) {
0241             parsedValue = new SVGColorImpl(SVGColorImpl::SVG_COLORTYPE_CURRENTCOLOR);
0242         } else { // TODO : svgcolor (iccColor)
0243             parsedValue = parseSVGColor();
0244         }
0245 
0246         if (parsedValue) {
0247             valueList->next();
0248         }
0249 
0250         break;
0251 
0252     case CSS_PROP_WRITING_MODE:
0253         // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
0254         if (id >= CSS_VAL_LR_TB && id <= CSS_VAL_TB) {
0255             valid_primitive = true;
0256         }
0257         break;
0258 
0259     case CSS_PROP_STROKE_WIDTH:         // <length> | inherit
0260     case CSS_PROP_STROKE_DASHOFFSET:
0261         valid_primitive = validUnit(value, FLength | FPercent, false);
0262         break;
0263 
0264     case CSS_PROP_STROKE_DASHARRAY:     // none | <dasharray> | inherit
0265         if (id == CSS_VAL_NONE) {
0266             valid_primitive = true;
0267         } else {
0268             parsedValue = parseSVGStrokeDasharray();
0269         }
0270 
0271         break;
0272 
0273     case CSS_PROP_KERNING:              // auto | normal | <length> | inherit
0274         if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL) {
0275             valid_primitive = true;
0276         } else {
0277             valid_primitive = validUnit(value, FLength, false);
0278         }
0279         break;
0280 
0281     case CSS_PROP_CLIP_PATH:    // <uri> | none | inherit
0282     case CSS_PROP_FILTER:
0283         if (id == CSS_VAL_NONE) {
0284             valid_primitive = true;
0285         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
0286             parsedValue = new CSSPrimitiveValueImpl(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
0287             if (parsedValue) {
0288                 valueList->next();
0289             }
0290         }
0291         break;
0292 
0293     /* shorthand properties */
0294     case CSS_PROP_MARKER: {
0295         const int properties[3] = { CSS_PROP_MARKER_START, CSS_PROP_MARKER_MID,
0296                                     CSS_PROP_MARKER_END
0297                                   };
0298         return parseShortHand(propId, properties, 3, important);
0299 
0300     }
0301     default:
0302         // If you crash here, it's because you added a css property and are not handling it
0303         // in either this switch statement or the one in CSSParser::parseValue
0304         //ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
0305         //return false;
0306         break;
0307     }
0308 
0309     if (valid_primitive) {
0310         if (id != 0) {
0311             parsedValue = new CSSPrimitiveValueImpl(id);
0312         } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
0313             parsedValue = new CSSPrimitiveValueImpl(domString(value->string), (CSSPrimitiveValue::UnitTypes)value->unit);
0314         } else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) {
0315             parsedValue = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
0316         } else if (value->unit >= Value::Q_EMS) {
0317             parsedValue = new CSSQuirkPrimitiveValueImpl(value->fValue, CSSPrimitiveValue::CSS_EMS);
0318         }
0319         valueList->next();
0320     }
0321     if (!parsedValue || (valueList->current() && !inShorthand())) {
0322         delete parsedValue;
0323         return false;
0324     }
0325 
0326     addProperty(propId, parsedValue, important);
0327     return true;
0328 }
0329 
0330 CSSValueImpl *CSSParser::parseSVGStrokeDasharray()
0331 {
0332     CSSValueListImpl *ret = new CSSValueListImpl(CSSValueListImpl::Comma);
0333     Value *value = valueList->current();
0334     bool valid_primitive = true;
0335     while (value) {
0336         valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, false);
0337         if (!valid_primitive) {
0338             break;
0339         }
0340         if (value->id != 0) {
0341             ret->append(new CSSPrimitiveValueImpl(value->id));
0342         } else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) {
0343             ret->append(new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
0344         }
0345         value = valueList->next();
0346         if (value && value->unit == Value::Operator && value->iValue == ',') {
0347             value = valueList->next();
0348         }
0349     }
0350     if (!valid_primitive) {
0351         delete ret;
0352         ret = nullptr;
0353     }
0354 
0355     return ret;
0356 }
0357 
0358 CSSValueImpl *CSSParser::parseSVGPaint()
0359 {
0360     CSSPrimitiveValueImpl *val;
0361 
0362     if (!(val = parseColorFromValue(valueList->current()/*, c, true*/))) {
0363         return new SVGPaintImpl();
0364     }
0365 
0366     SVGPaintImpl *paint = new SVGPaintImpl(QColor(val->getRGBColorValue()));
0367     delete val;
0368     return paint;
0369 }
0370 
0371 CSSValueImpl *CSSParser::parseSVGColor()
0372 {
0373     CSSPrimitiveValueImpl *val;
0374     if (!(val = parseColorFromValue(valueList->current()/*, c, true*/))) {
0375         return nullptr;
0376     }
0377     SVGColorImpl *color = new SVGColorImpl(QColor(val->getRGBColorValue()));
0378     delete val;
0379     return color;
0380 }
0381 
0382 }
0383