| /* |
| Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org> |
| 2004, 2005 Rob Buis <buis@kde.org> |
| Copyright (C) 2005, 2006 Apple Computer, Inc. |
| |
| This file is part of the KDE project |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public License |
| along with this library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. |
| */ |
| |
| #include "config.h" |
| #if SVG_SUPPORT |
| |
| #include "ksvg.h" |
| |
| #include "SVGPaint.h" |
| #include "CSSInheritedValue.h" |
| #include "CSSInitialValue.h" |
| #include "cssparser.h" |
| #include "CSSPropertyNames.h" |
| #include "CSSQuirkPrimitiveValue.h" |
| #include "CSSValueKeywords.h" |
| #include "CSSValueList.h" |
| #include "ksvgcssproperties.c" |
| #include "ksvgcssvalues.c" |
| |
| using namespace std; |
| |
| namespace WebCore { |
| |
| typedef Value KDOMCSSValue; |
| typedef ValueList KDOMCSSValueList; |
| |
| bool CSSParser::parseSVGValue(int propId, bool important) |
| { |
| if (!valueList) |
| return false; |
| |
| KDOMCSSValue *value = valueList->current(); |
| if (!value) |
| return false; |
| |
| int id = value->id; |
| |
| int num = inShorthand() ? 1 : valueList->size(); |
| |
| if (id == CSS_VAL_INHERIT) { |
| if (num != 1) |
| return false; |
| addProperty(propId, new CSSInheritedValue(), important); |
| return true; |
| } else if (id == CSS_VAL_INITIAL) { |
| if (num != 1) |
| return false; |
| addProperty(propId, new CSSInitialValue(), important); |
| return true; |
| } |
| |
| bool valid_primitive = false; |
| CSSValue *parsedValue = 0; |
| |
| switch(propId) |
| { |
| /* The comment to the right defines all valid value of these |
| * properties as defined in SVG 1.1, Appendix N. Property index */ |
| case SVGCSS_PROP_ALIGNMENT_BASELINE: |
| // auto | baseline | before-edge | text-before-edge | middle | |
| // central | after-edge | text-after-edge | ideographic | alphabetic | |
| // hanging | mathematical | inherit |
| if (id == CSS_VAL_AUTO || id == CSS_VAL_BASELINE || id == CSS_VAL_MIDDLE || |
| (id >= SVGCSS_VAL_BEFORE_EDGE && id <= SVGCSS_VAL_MATHEMATICAL)) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_BASELINE_SHIFT: |
| // baseline | super | sub | <percentage> | <length> | inherit |
| if (id == CSS_VAL_BASELINE || id == CSS_VAL_SUB || |
| id >= CSS_VAL_SUPER) |
| valid_primitive = true; |
| else |
| valid_primitive = validUnit(value, FLength|FPercent, false); |
| break; |
| |
| case SVGCSS_PROP_DOMINANT_BASELINE: |
| // auto | use-script | no-change | reset-size | ideographic | |
| // alphabetic | hanging | mathematical | central | middle | |
| // text-after-edge | text-before-edge | inherit |
| if (id == CSS_VAL_AUTO || id == CSS_VAL_MIDDLE || |
| (id >= SVGCSS_VAL_USE_SCRIPT && id <= SVGCSS_VAL_RESET_SIZE) || |
| (id >= SVGCSS_VAL_CENTRAL && id <= SVGCSS_VAL_MATHEMATICAL)) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_ENABLE_BACKGROUND: |
| // accumulate | new [x] [y] [width] [height] | inherit |
| if (id == SVGCSS_VAL_ACCUMULATE) // TODO : new |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_MARKER_START: |
| case SVGCSS_PROP_MARKER_MID: |
| case SVGCSS_PROP_MARKER_END: |
| case SVGCSS_PROP_MASK: |
| if (id == CSS_VAL_NONE) |
| valid_primitive = true; |
| else if (value->unit == CSSPrimitiveValue::CSS_URI) |
| { |
| parsedValue = new CSSPrimitiveValue(domString(value->string), CSSPrimitiveValue::CSS_URI); |
| if (parsedValue) |
| valueList->next(); |
| } |
| break; |
| |
| case SVGCSS_PROP_CLIP_RULE: // nonzero | evenodd | inherit |
| case SVGCSS_PROP_FILL_RULE: |
| if (id == SVGCSS_VAL_NONZERO || id == SVGCSS_VAL_EVENODD) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_STROKE_MITERLIMIT: // <miterlimit> | inherit |
| valid_primitive = validUnit(value, FInteger|FNonNeg, false); |
| break; |
| |
| case SVGCSS_PROP_STROKE_LINEJOIN: // miter | round | bevel | inherit |
| if (id == SVGCSS_VAL_MITER || id == CSS_VAL_ROUND || id == SVGCSS_VAL_BEVEL) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_STROKE_LINECAP: // butt | round | square | inherit |
| if (id == SVGCSS_VAL_BUTT || id == CSS_VAL_ROUND || id == CSS_VAL_SQUARE) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_STROKE_OPACITY: // <opacity-value> | inherit |
| case SVGCSS_PROP_FILL_OPACITY: |
| case SVGCSS_PROP_STOP_OPACITY: |
| case SVGCSS_PROP_FLOOD_OPACITY: |
| valid_primitive = (!id && validUnit(value, FNumber|FPercent, false)); |
| break; |
| |
| case SVGCSS_PROP_SHAPE_RENDERING: |
| // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit |
| if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED || |
| id == SVGCSS_VAL_CRISPEDGES || id == SVGCSS_VAL_GEOMETRICPRECISION) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_TEXT_RENDERING: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit |
| if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED || id == SVGCSS_VAL_OPTIMIZELEGIBILITY || |
| id == SVGCSS_VAL_GEOMETRICPRECISION) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_IMAGE_RENDERING: // auto | optimizeSpeed | |
| case SVGCSS_PROP_COLOR_RENDERING: // optimizeQuality | inherit |
| if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED || |
| id == SVGCSS_VAL_OPTIMIZEQUALITY) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_COLOR_PROFILE: // auto | sRGB | <name> | <uri> inherit |
| if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_SRGB) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_COLOR_INTERPOLATION: // auto | sRGB | linearRGB | inherit |
| case SVGCSS_PROP_COLOR_INTERPOLATION_FILTERS: |
| if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_SRGB || id == SVGCSS_VAL_LINEARRGB) |
| valid_primitive = true; |
| break; |
| |
| /* Start of supported CSS properties with validation. This is needed for parseShortHand to work |
| * correctly and allows optimization in applyRule(..) |
| */ |
| |
| case SVGCSS_PROP_POINTER_EVENTS: |
| // visiblePainted | visibleFill | visibleStroke | visible | |
| // painted | fill | stroke || all | inherit |
| if (id == CSS_VAL_VISIBLE || |
| (id >= SVGCSS_VAL_VISIBLEPAINTED && id <= SVGCSS_VAL_ALL)) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_TEXT_ANCHOR: // start | middle | end | inherit |
| if (id == CSS_VAL_START || id == CSS_VAL_MIDDLE || id == CSS_VAL_END) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_GLYPH_ORIENTATION_VERTICAL: // auto | <angle> | inherit |
| if (id == CSS_VAL_AUTO) |
| { |
| valid_primitive = true; |
| break; |
| } |
| /* fallthrough intentional */ |
| case SVGCSS_PROP_GLYPH_ORIENTATION_HORIZONTAL: // <angle> | inherit |
| if (value->unit == CSSPrimitiveValue::CSS_DEG) |
| parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_DEG); |
| else if (value->unit == CSSPrimitiveValue::CSS_GRAD) |
| parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_GRAD); |
| else if (value->unit == CSSPrimitiveValue::CSS_RAD) |
| parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_RAD); |
| break; |
| |
| case SVGCSS_PROP_FILL: // <paint> | inherit |
| case SVGCSS_PROP_STROKE: // <paint> | inherit |
| { |
| if (id == CSS_VAL_NONE) |
| parsedValue = new SVGPaint(SVG_PAINTTYPE_NONE); |
| else if (id == SVGCSS_VAL_CURRENTCOLOR) |
| parsedValue = new SVGPaint(SVG_PAINTTYPE_CURRENTCOLOR); |
| else if (value->unit == CSSPrimitiveValue::CSS_URI) |
| parsedValue = new SVGPaint(SVG_PAINTTYPE_URI, domString(value->string).impl()); |
| else |
| parsedValue = parseSVGPaint(); |
| |
| if (parsedValue) |
| valueList->next(); |
| } |
| break; |
| |
| case CSS_PROP_COLOR: // <color> | inherit |
| if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || |
| (id >= SVGCSS_VAL_ALICEBLUE && id <= SVGCSS_VAL_YELLOWGREEN)) |
| parsedValue = new SVGColor(domString(value->string).impl()); |
| else |
| parsedValue = parseSVGColor(); |
| |
| if (parsedValue) |
| valueList->next(); |
| break; |
| |
| case SVGCSS_PROP_STOP_COLOR: // TODO : icccolor |
| case SVGCSS_PROP_FLOOD_COLOR: |
| case SVGCSS_PROP_LIGHTING_COLOR: |
| if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || |
| (id >= SVGCSS_VAL_ALICEBLUE && id <= SVGCSS_VAL_YELLOWGREEN)) |
| parsedValue = new SVGColor(domString(value->string).impl()); |
| else if (id == SVGCSS_VAL_CURRENTCOLOR) |
| parsedValue = new SVGColor(SVGColor::SVG_COLORTYPE_CURRENTCOLOR); |
| else // TODO : svgcolor (iccColor) |
| parsedValue = parseSVGColor(); |
| |
| if (parsedValue) |
| valueList->next(); |
| |
| break; |
| |
| case SVGCSS_PROP_WRITING_MODE: |
| // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit |
| if (id >= SVGCSS_VAL_LR_TB && id <= SVGCSS_VAL_TB) |
| valid_primitive = true; |
| break; |
| |
| case SVGCSS_PROP_STROKE_WIDTH: // <length> | inherit |
| case SVGCSS_PROP_STROKE_DASHOFFSET: |
| valid_primitive = validUnit(value, FLength | FPercent, false); |
| break; |
| case SVGCSS_PROP_STROKE_DASHARRAY: // none | <dasharray> | inherit |
| if (id == CSS_VAL_NONE) |
| valid_primitive = true; |
| else |
| parsedValue = parseSVGStrokeDasharray(); |
| |
| break; |
| |
| case SVGCSS_PROP_KERNING: // auto | normal | <length> | inherit |
| if (id == CSS_VAL_AUTO) |
| valid_primitive = true; |
| else |
| valid_primitive = validUnit(value, FLength, false); |
| break; |
| |
| case SVGCSS_PROP_CLIP_PATH: // <uri> | none | inherit |
| case SVGCSS_PROP_FILTER: |
| if (id == CSS_VAL_NONE) |
| valid_primitive = true; |
| else if (value->unit == CSSPrimitiveValue::CSS_URI) |
| { |
| parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit); |
| if (parsedValue) |
| valueList->next(); |
| } |
| break; |
| |
| /* shorthand properties */ |
| case SVGCSS_PROP_MARKER: |
| { |
| const int properties[3] = { SVGCSS_PROP_MARKER_START, |
| SVGCSS_PROP_MARKER_MID, |
| SVGCSS_PROP_MARKER_END }; |
| return parseShorthand(propId, properties, 3, important); |
| } |
| default: |
| return false; |
| } |
| |
| if (valid_primitive) |
| { |
| if (id != 0) |
| parsedValue = new CSSPrimitiveValue(id); |
| else if (value->unit == CSSPrimitiveValue::CSS_STRING) |
| parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit); |
| else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) |
| parsedValue = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); |
| else if (value->unit >= KDOMCSSValue::Q_EMS) |
| parsedValue = new CSSQuirkPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_EMS); |
| valueList->next(); |
| } |
| if (parsedValue) { |
| if (!valueList->current() || inShorthand()) { |
| addProperty(propId, parsedValue, important); |
| return true; |
| } |
| delete parsedValue; |
| } |
| return false; |
| } |
| |
| CSSValue* CSSParser::parseSVGStrokeDasharray() |
| { |
| CSSValueList* ret = new CSSValueList; |
| KDOMCSSValue* value = valueList->current(); |
| bool valid_primitive = true; |
| while(valid_primitive && value) { |
| valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false); |
| if (value->id != 0) |
| ret->append(new CSSPrimitiveValue(value->id)); |
| else if (value->unit == CSSPrimitiveValue::CSS_STRING) |
| ret->append(new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit)); |
| else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) |
| ret->append(new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit)); |
| value = valueList->next(); |
| if (value && value->unit == KDOMCSSValue::Operator && value->iValue == ',') |
| value = valueList->next(); |
| } |
| if (!valid_primitive) { |
| delete ret; |
| ret = 0; |
| } |
| |
| return ret; |
| } |
| |
| CSSValue *CSSParser::parseSVGPaint() |
| { |
| KDOMCSSValue *value = valueList->current(); |
| if (!strict && value->unit == CSSPrimitiveValue::CSS_NUMBER && |
| value->fValue >= 0. && value->fValue < 1000000.) { |
| String str = String::sprintf("%06d", (int)(value->fValue+.5)); |
| return new SVGPaint(SVG_PAINTTYPE_RGBCOLOR, 0, str.impl()); |
| } else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR) { |
| String str = "#" + domString(value->string); |
| return new SVGPaint(SVG_PAINTTYPE_RGBCOLOR, 0, str.impl()); |
| } else if (value->unit == CSSPrimitiveValue::CSS_IDENT || |
| (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) |
| return new SVGPaint(SVG_PAINTTYPE_RGBCOLOR, 0, domString(value->string).impl()); |
| else if (value->unit == KDOMCSSValue::Function && value->function->args != 0 && |
| domString(value->function->name).lower() == "rgb(") |
| { |
| KDOMCSSValueList *args = value->function->args; |
| KDOMCSSValue *v = args->current(); |
| if (!validUnit(v, FInteger|FPercent, true)) |
| return 0; |
| int r = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.)); |
| v = args->next(); |
| if (v->unit != KDOMCSSValue::Operator && v->iValue != ',') |
| return 0; |
| v = args->next(); |
| if (!validUnit(v, FInteger|FPercent, true)) |
| return 0; |
| int g = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.)); |
| v = args->next(); |
| if (v->unit != KDOMCSSValue::Operator && v->iValue != ',') |
| return 0; |
| v = args->next(); |
| if (!validUnit(v, FInteger|FPercent, true)) |
| return 0; |
| int b = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.)); |
| r = max(0, min(255, r)); |
| g = max(0, min(255, g)); |
| b = max(0, min(255, b)); |
| |
| return new SVGPaint(SVG_PAINTTYPE_RGBCOLOR, 0, String::sprintf("rgb(%d, %d, %d)", r, g, b).impl()); |
| } |
| else |
| return 0; |
| |
| return new SVGPaint(); |
| } |
| |
| CSSValue *CSSParser::parseSVGColor() |
| { |
| KDOMCSSValue *value = valueList->current(); |
| if (!strict && value->unit == CSSPrimitiveValue::CSS_NUMBER && value->fValue >= 0. && value->fValue < 1000000.) |
| return new SVGColor(String::sprintf("%06d", (int)(value->fValue+.5)).impl()); |
| else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR) { |
| String str = "#" + domString(value->string); |
| return new SVGColor(str.impl()); |
| } else if (value->unit == CSSPrimitiveValue::CSS_IDENT || (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) |
| return new SVGColor(domString(value->string).impl()); |
| else if (value->unit == KDOMCSSValue::Function && value->function->args != 0 && domString(value->function->name).lower() == "rgb(") { |
| KDOMCSSValueList *args = value->function->args; |
| KDOMCSSValue *v = args->current(); |
| if (!validUnit(v, FInteger|FPercent, true)) |
| return 0; |
| int r = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.)); |
| v = args->next(); |
| if (v->unit != Value::Operator && v->iValue != ',') |
| return 0; |
| v = args->next(); |
| if (!validUnit(v, FInteger|FPercent, true)) |
| return 0; |
| int g = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.)); |
| v = args->next(); |
| if (v->unit != Value::Operator && v->iValue != ',') |
| return 0; |
| v = args->next(); |
| if (!validUnit(v, FInteger|FPercent, true)) |
| return 0; |
| int b = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.)); |
| r = max(0, min(255, r)); |
| g = max(0, min(255, g)); |
| b = max(0, min(255, b)); |
| |
| return new SVGColor(String::sprintf("rgb(%d, %d, %d)", r, g, b).impl()); |
| } |
| else |
| return 0; |
| |
| return new SVGPaint(); |
| } |
| |
| } |
| |
| #endif // SVG_SUPPORT |
| |
| // vim:ts=4:noet |