/* Copyright (C) 2005 Apple Computer, Inc. Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann Copyright (C) 2004, 2005 Rob Buis Copyright (C) 2007 Alexey Proskuryakov Copyright (C) 2009 Maksim Orlovich Based on khtml css code by: Copyright (C) 1999-2003 Lars Knoll Copyright (C) 2003 Apple Computer, Inc. Copyright (C) 2004 Allan Sandfeld Jensen Copyright (C) 2004 Germain Garand 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "cssstyleselector.h" #include "css_valueimpl.h" #include "css_svgvalueimpl.h" #include "cssvalues.h" #include "SVGNames.h" #include "SVGRenderStyle.h" #include "SVGRenderStyleDefs.h" #include "SVGStyledElement.h" #include #define HANDLE_INHERIT(prop, Prop) \ if (isInherit) \ {\ svgstyle->set##Prop(parentStyle->svgStyle()->prop());\ return;\ } #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ HANDLE_INHERIT(prop, Prop) \ else if (isInitial) \ svgstyle->set##Prop(SVGRenderStyle::initial##Prop()); #define HANDLE_INHERIT_COND(propID, prop, Prop) \ if (id == propID) \ {\ svgstyle->set##Prop(parentStyle->svgStyle()->prop());\ return;\ } #define HANDLE_INITIAL_COND(propID, Prop) \ if (id == propID) \ {\ svgstyle->set##Prop(SVGRenderStyle::initial##Prop());\ return;\ } #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \ if (id == propID) { \ svgstyle->set##Prop(SVGRenderStyle::initial##Value()); \ return; \ } namespace khtml { using namespace DOM; using namespace WebCore; static SVGPaintImpl* toPaint(CSSValueImpl* val) { if (val->cssValueType() != DOM::CSSValue::CSS_SVG_VALUE) return 0; SVGCSSValueImpl* svgVal = static_cast(val); if (svgVal->isSVGPaint()) return static_cast(svgVal); else return 0; } static SVGColorImpl* toColor(CSSValueImpl* val) { if (val->cssValueType() != DOM::CSSValue::CSS_SVG_VALUE) return 0; SVGCSSValueImpl* svgVal = static_cast(val); if (svgVal->isSVGColor()) return static_cast(svgVal); else return 0; } static float roundToNearestGlyphOrientationAngle(float angle) { angle = fabsf(fmodf(angle, 360.0f)); if (angle <= 45.0f || angle > 315.0f) return 0.0f; else if (angle > 45.0f && angle <= 135.0f) return 90.0f; else if (angle > 135.0f && angle <= 225.0f) return 180.0f; return 270.0f; } static int angleToGlyphOrientation(float angle) { angle = roundToNearestGlyphOrientationAngle(angle); if (angle == 0.0f) return GO_0DEG; else if (angle == 90.0f) return GO_90DEG; else if (angle == 180.0f) return GO_180DEG; else if (angle == 270.0f) return GO_270DEG; return -1; } static EColorInterpolation colorInterpolationForValue(DOM::CSSPrimitiveValueImpl* primitiveValue) { if (!primitiveValue) return CI_AUTO; switch (primitiveValue->getIdent()) { case CSS_VAL_SRGB: return CI_SRGB; case CSS_VAL_LINEARRGB: return CI_LINEARRGB; case CSS_VAL_AUTO: default: return CI_AUTO; } } void CSSStyleSelector::applySVGRule(int id, DOM::CSSValueImpl* value) { CSSPrimitiveValueImpl* primitiveValue = 0; if (value->isPrimitiveValue()) primitiveValue = static_cast(value); SVGRenderStyle* svgstyle = style->accessSVGStyle(); unsigned short valueType = value->cssValueType(); bool isInherit = parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT; bool isInitial = valueType == CSSPrimitiveValue::CSS_INITIAL || (!parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT); // What follows is a list that maps the CSS properties into their // corresponding front-end RenderStyle values. Shorthands(e.g. border, // background) occur in this list as well and are only hit when mapping // "inherit" or "initial" into front-end values. switch (id) { // ident only properties case CSS_PROP_ALIGNMENT_BASELINE: { HANDLE_INHERIT_AND_INITIAL(alignmentBaseline, AlignmentBaseline) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_AUTO: svgstyle->setAlignmentBaseline(AB_AUTO); break; case CSS_VAL_BASELINE: svgstyle->setAlignmentBaseline(AB_BASELINE); break; case CSS_VAL_BEFORE_EDGE: svgstyle->setAlignmentBaseline(AB_BEFORE_EDGE); break; case CSS_VAL_TEXT_BEFORE_EDGE: svgstyle->setAlignmentBaseline(AB_TEXT_BEFORE_EDGE); break; case CSS_VAL_MIDDLE: svgstyle->setAlignmentBaseline(AB_MIDDLE); break; case CSS_VAL_CENTRAL: svgstyle->setAlignmentBaseline(AB_CENTRAL); break; case CSS_VAL_AFTER_EDGE: svgstyle->setAlignmentBaseline(AB_AFTER_EDGE); break; case CSS_VAL_TEXT_AFTER_EDGE: svgstyle->setAlignmentBaseline(AB_TEXT_AFTER_EDGE); break; case CSS_VAL_IDEOGRAPHIC: svgstyle->setAlignmentBaseline(AB_IDEOGRAPHIC); break; case CSS_VAL_ALPHABETIC: svgstyle->setAlignmentBaseline(AB_ALPHABETIC); break; case CSS_VAL_HANGING: svgstyle->setAlignmentBaseline(AB_HANGING); break; case CSS_VAL_MATHEMATICAL: svgstyle->setAlignmentBaseline(AB_MATHEMATICAL); break; default: break; } break; } case CSS_PROP_BASELINE_SHIFT: { HANDLE_INHERIT_AND_INITIAL(baselineShift, BaselineShift); if (!primitiveValue) break; if (primitiveValue->getIdent()) { switch (primitiveValue->getIdent()) { case CSS_VAL_BASELINE: svgstyle->setBaselineShift(BS_BASELINE); break; case CSS_VAL_SUB: svgstyle->setBaselineShift(BS_SUB); break; case CSS_VAL_SUPER: svgstyle->setBaselineShift(BS_SUPER); break; default: break; } } else { svgstyle->setBaselineShift(BS_LENGTH); svgstyle->setBaselineShiftValue(primitiveValue); } break; } case CSS_PROP_KERNING: { if (isInherit) { HANDLE_INHERIT_COND(CSS_PROP_KERNING, kerning, Kerning) return; } else if (isInitial) { HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_KERNING, Kerning, Kerning) return; } svgstyle->setKerning(primitiveValue); break; } case CSS_PROP_POINTER_EVENTS: { HANDLE_INHERIT_AND_INITIAL(pointerEvents, PointerEvents) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_NONE: svgstyle->setPointerEvents(PE_NONE); break; case CSS_VAL_STROKE: svgstyle->setPointerEvents(PE_STROKE); break; case CSS_VAL_FILL: svgstyle->setPointerEvents(PE_FILL); break; case CSS_VAL_PAINTED: svgstyle->setPointerEvents(PE_PAINTED); break; case CSS_VAL_VISIBLE: svgstyle->setPointerEvents(PE_VISIBLE); break; case CSS_VAL_VISIBLESTROKE: svgstyle->setPointerEvents(PE_VISIBLE_STROKE); break; case CSS_VAL_VISIBLEFILL: svgstyle->setPointerEvents(PE_VISIBLE_FILL); break; case CSS_VAL_VISIBLEPAINTED: svgstyle->setPointerEvents(PE_VISIBLE_PAINTED); break; case CSS_VAL_ALL: svgstyle->setPointerEvents(PE_ALL); break; default: break; } break; } case CSS_PROP_DOMINANT_BASELINE: { HANDLE_INHERIT_AND_INITIAL(dominantBaseline, DominantBaseline) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_AUTO: svgstyle->setDominantBaseline(DB_AUTO); break; case CSS_VAL_USE_SCRIPT: svgstyle->setDominantBaseline(DB_USE_SCRIPT); break; case CSS_VAL_NO_CHANGE: svgstyle->setDominantBaseline(DB_NO_CHANGE); break; case CSS_VAL_RESET_SIZE: svgstyle->setDominantBaseline(DB_RESET_SIZE); break; case CSS_VAL_IDEOGRAPHIC: svgstyle->setDominantBaseline(DB_IDEOGRAPHIC); break; case CSS_VAL_ALPHABETIC: svgstyle->setDominantBaseline(DB_ALPHABETIC); break; case CSS_VAL_HANGING: svgstyle->setDominantBaseline(DB_HANGING); break; case CSS_VAL_MATHEMATICAL: svgstyle->setDominantBaseline(DB_MATHEMATICAL); break; case CSS_VAL_CENTRAL: svgstyle->setDominantBaseline(DB_CENTRAL); break; case CSS_VAL_MIDDLE: svgstyle->setDominantBaseline(DB_MIDDLE); break; case CSS_VAL_TEXT_AFTER_EDGE: svgstyle->setDominantBaseline(DB_TEXT_AFTER_EDGE); break; case CSS_VAL_TEXT_BEFORE_EDGE: svgstyle->setDominantBaseline(DB_TEXT_BEFORE_EDGE); break; default: break; } break; } case CSS_PROP_COLOR_INTERPOLATION: { HANDLE_INHERIT_AND_INITIAL(colorInterpolation, ColorInterpolation); svgstyle->setColorInterpolation(colorInterpolationForValue(primitiveValue)); break; } case CSS_PROP_COLOR_INTERPOLATION_FILTERS: { HANDLE_INHERIT_AND_INITIAL(colorInterpolationFilters, ColorInterpolationFilters) svgstyle->setColorInterpolationFilters(colorInterpolationForValue(primitiveValue)); break; } case CSS_PROP_COLOR_RENDERING: { HANDLE_INHERIT_AND_INITIAL(colorRendering, ColorRendering) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_AUTO: svgstyle->setColorRendering(CR_AUTO); break; case CSS_VAL_OPTIMIZESPEED: svgstyle->setColorRendering(CR_OPTIMIZESPEED); break; case CSS_VAL_OPTIMIZEQUALITY: svgstyle->setColorRendering(CR_OPTIMIZEQUALITY); break; default: break; } break; } case CSS_PROP_CLIP_RULE: { HANDLE_INHERIT_AND_INITIAL(clipRule, ClipRule) if (primitiveValue) svgstyle->setClipRule((primitiveValue->getIdent() == CSS_VAL_NONZERO) ? RULE_NONZERO : RULE_EVENODD); break; } case CSS_PROP_FILL_RULE: { HANDLE_INHERIT_AND_INITIAL(fillRule, FillRule) if (primitiveValue) svgstyle->setFillRule((primitiveValue->getIdent() == CSS_VAL_NONZERO) ? RULE_NONZERO : RULE_EVENODD); break; } case CSS_PROP_STROKE_LINEJOIN: { HANDLE_INHERIT_AND_INITIAL(joinStyle, JoinStyle) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_MITER: svgstyle->setJoinStyle(khtml::MiterJoin); break; case CSS_VAL_ROUND: svgstyle->setJoinStyle(khtml::RoundJoin); break; case CSS_VAL_BEVEL: svgstyle->setJoinStyle(khtml::BevelJoin); break; default: break; } break; } case CSS_PROP_IMAGE_RENDERING: { HANDLE_INHERIT_AND_INITIAL(imageRendering, ImageRendering) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_AUTO: svgstyle->setImageRendering(IR_AUTO); break; case CSS_VAL_OPTIMIZESPEED: svgstyle->setImageRendering(IR_OPTIMIZESPEED); break; case CSS_VAL_OPTIMIZEQUALITY: svgstyle->setImageRendering(IR_OPTIMIZEQUALITY); break; default: break; } break; } case CSS_PROP_SHAPE_RENDERING: { HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_AUTO: svgstyle->setShapeRendering(SR_AUTO); break; case CSS_VAL_OPTIMIZESPEED: svgstyle->setShapeRendering(SR_OPTIMIZESPEED); break; case CSS_VAL_CRISPEDGES: svgstyle->setShapeRendering(SR_CRISPEDGES); break; case CSS_VAL_GEOMETRICPRECISION: svgstyle->setShapeRendering(SR_GEOMETRICPRECISION); break; default: break; } break; } case CSS_PROP_TEXT_RENDERING: { HANDLE_INHERIT_AND_INITIAL(textRendering, TextRendering) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_AUTO: svgstyle->setTextRendering(TR_AUTO); break; case CSS_VAL_OPTIMIZESPEED: svgstyle->setTextRendering(TR_OPTIMIZESPEED); break; case CSS_VAL_OPTIMIZELEGIBILITY: svgstyle->setTextRendering(TR_OPTIMIZELEGIBILITY); break; case CSS_VAL_GEOMETRICPRECISION: svgstyle->setTextRendering(TR_GEOMETRICPRECISION); break; default: break; } break; } // end of ident only properties case CSS_PROP_FILL: { HANDLE_INHERIT_AND_INITIAL(fillPaint, FillPaint) if (SVGPaintImpl* paint = toPaint(value)) svgstyle->setFillPaint(paint); break; } case CSS_PROP_STROKE: { HANDLE_INHERIT_AND_INITIAL(strokePaint, StrokePaint) if (SVGPaintImpl* paint = toPaint(value)) svgstyle->setStrokePaint(paint); break; } case CSS_PROP_STROKE_WIDTH: { HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth) if (!primitiveValue) return; svgstyle->setStrokeWidth(primitiveValue); break; } case CSS_PROP_STROKE_DASHARRAY: { HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray) if (!primitiveValue && value && value->isValueList()) { CSSValueListImpl* dashes = static_cast(value); svgstyle->setStrokeDashArray(dashes); } break; } case CSS_PROP_STROKE_DASHOFFSET: { HANDLE_INHERIT_AND_INITIAL(strokeDashOffset, StrokeDashOffset) if (!primitiveValue) return; svgstyle->setStrokeDashOffset(primitiveValue); break; } case CSS_PROP_FILL_OPACITY: { HANDLE_INHERIT_AND_INITIAL(fillOpacity, FillOpacity) if (!primitiveValue) return; float f = 0.0f; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_PERCENTAGE) f = primitiveValue->floatValue() / 100.0f; else if (type == CSSPrimitiveValue::CSS_NUMBER) f = primitiveValue->floatValue(); else return; svgstyle->setFillOpacity(f); break; } case CSS_PROP_STROKE_OPACITY: { HANDLE_INHERIT_AND_INITIAL(strokeOpacity, StrokeOpacity) if (!primitiveValue) return; float f = 0.0f; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_PERCENTAGE) f = primitiveValue->floatValue() / 100.0f; else if (type == CSSPrimitiveValue::CSS_NUMBER) f = primitiveValue->floatValue(); else return; svgstyle->setStrokeOpacity(f); break; } case CSS_PROP_STOP_OPACITY: { HANDLE_INHERIT_AND_INITIAL(stopOpacity, StopOpacity) if (!primitiveValue) return; float f = 0.0f; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_PERCENTAGE) f = primitiveValue->floatValue() / 100.0f; else if (type == CSSPrimitiveValue::CSS_NUMBER) f = primitiveValue->floatValue(); else return; svgstyle->setStopOpacity(f); break; } case CSS_PROP_MARKER_START: { HANDLE_INHERIT_AND_INITIAL(startMarker, StartMarker) if (!primitiveValue) return; String s; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_URI) s = primitiveValue->getStringValue(); else return; svgstyle->setStartMarker(s); break; } case CSS_PROP_MARKER_MID: { HANDLE_INHERIT_AND_INITIAL(midMarker, MidMarker) if (!primitiveValue) return; String s; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_URI) s = primitiveValue->getStringValue(); else return; svgstyle->setMidMarker(s); break; } case CSS_PROP_MARKER_END: { HANDLE_INHERIT_AND_INITIAL(endMarker, EndMarker) if (!primitiveValue) return; String s; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_URI) s = primitiveValue->getStringValue(); else return; svgstyle->setEndMarker(s); break; } case CSS_PROP_STROKE_LINECAP: { HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle) if (!primitiveValue) break; switch (primitiveValue->getIdent()) { case CSS_VAL_BUTT: svgstyle->setCapStyle(ButtCap); break; case CSS_VAL_ROUND: svgstyle->setCapStyle(RoundCap); break; case CSS_VAL_SQUARE: svgstyle->setCapStyle(SquareCap); break; default: break; } break; } case CSS_PROP_STROKE_MITERLIMIT: { HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit) if (!primitiveValue) return; float f = 0.0f; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_NUMBER) f = primitiveValue->floatValue(); else return; svgstyle->setStrokeMiterLimit(f); break; } case CSS_PROP_FILTER: { HANDLE_INHERIT_AND_INITIAL(filter, Filter) if (!primitiveValue) return; String s; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_URI) s = primitiveValue->getStringValue(); else return; svgstyle->setFilter(s); break; } case CSS_PROP_MASK: { HANDLE_INHERIT_AND_INITIAL(maskElement, MaskElement) if (!primitiveValue) return; String s; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_URI) s = primitiveValue->getStringValue(); else return; svgstyle->setMaskElement(s); break; } case CSS_PROP_CLIP_PATH: { HANDLE_INHERIT_AND_INITIAL(clipPath, ClipPath) if (!primitiveValue) return; String s; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_URI) s = primitiveValue->getStringValue(); else return; svgstyle->setClipPath(s); break; } case CSS_PROP_TEXT_ANCHOR: { HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor) if (primitiveValue) { switch (primitiveValue->getIdent()) { case CSS_VAL_START: svgstyle->setTextAnchor(TA_START); break; case CSS_VAL_MIDDLE: svgstyle->setTextAnchor(TA_MIDDLE); break; case CSS_VAL_END: svgstyle->setTextAnchor(TA_END); break; } } break; } case CSS_PROP_WRITING_MODE: { HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode) if (!primitiveValue) return; switch (primitiveValue->getIdent()) { case CSS_VAL_LR_TB: svgstyle->setWritingMode(WM_LRTB); break; case CSS_VAL_LR: svgstyle->setWritingMode(WM_LR); break; case CSS_VAL_RL_TB: svgstyle->setWritingMode(WM_RLTB); break; case CSS_VAL_RL: svgstyle->setWritingMode(WM_RL); break; case CSS_VAL_TB_RL: svgstyle->setWritingMode(WM_TBRL); break; case CSS_VAL_TB: svgstyle->setWritingMode(WM_TB); break; default: break; } break; } case CSS_PROP_STOP_COLOR: { HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor); SVGColorImpl* c = toColor(value); if (!c) break; QColor col; if (c->colorType() == SVGColorImpl::SVG_COLORTYPE_CURRENTCOLOR) col = style->color(); else col = c->color(); svgstyle->setStopColor(col); break; } case CSS_PROP_LIGHTING_COLOR: { HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor); SVGColorImpl* c = toColor(value); if (!c) break; QColor col; if (c->colorType() == SVGColorImpl::SVG_COLORTYPE_CURRENTCOLOR) col = style->color(); else col = c->color(); svgstyle->setLightingColor(col); break; } case CSS_PROP_FLOOD_OPACITY: { HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity) if (!primitiveValue) return; float f = 0.0f; int type = primitiveValue->primitiveType(); if (type == CSSPrimitiveValue::CSS_PERCENTAGE) f = primitiveValue->floatValue() / 100.0f; else if (type == CSSPrimitiveValue::CSS_NUMBER) f = primitiveValue->floatValue(); else return; svgstyle->setFloodOpacity(f); break; } case CSS_PROP_FLOOD_COLOR: { QColor col; if (isInitial) col = SVGRenderStyle::initialFloodColor(); else { SVGColorImpl* c = toColor(value); if (!c) break; if (c->colorType() == SVGColorImpl::SVG_COLORTYPE_CURRENTCOLOR) col = style->color(); else col = c->color(); } svgstyle->setFloodColor(col); break; } case CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL: { HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal) if (!primitiveValue) return; if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { int orientation = angleToGlyphOrientation(primitiveValue->floatValue()); ASSERT(orientation != -1); svgstyle->setGlyphOrientationHorizontal((EGlyphOrientation) orientation); } break; } case CSS_PROP_GLYPH_ORIENTATION_VERTICAL: { HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical) if (!primitiveValue) return; if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { int orientation = angleToGlyphOrientation(primitiveValue->floatValue()); ASSERT(orientation != -1); svgstyle->setGlyphOrientationVertical((EGlyphOrientation) orientation); } else if (primitiveValue->getIdent() == CSS_VAL_AUTO) svgstyle->setGlyphOrientationVertical(GO_AUTO); break; } case CSS_PROP_ENABLE_BACKGROUND: // Silently ignoring this property for now // http://bugs.webkit.org/show_bug.cgi?id=6022 break; default: // If you crash here, it's because you added a css property and are not handling it // in either this switch statement or the one in CSSStyleSelector::applyProperty kWarning() << "unimplemented property" << id << getPropertyName(id).string(); return; } } }