/* Copyright (C) 2001-2003 KSVG Team 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 <kdebug.h> #include <qrect.h> #include "CanvasItem.h" #include "KSVGCanvas.h" #include "SVGPaint.h" #include "SVGColorImpl.h" #include "SVGPaintImpl.h" #include "SVGHelperImpl.h" #include "SVGLengthImpl.h" #include "SVGDocumentImpl.h" #include "SVGStylableImpl.h" #include "SVGSVGElementImpl.h" #include "SVGStringListImpl.h" #include "SVGImageElementImpl.h" #include "SVGURIReferenceImpl.h" #include "SVGAnimatedLengthImpl.h" #include "SVGColorProfileElementImpl.h" #include "SVGAnimatedLengthListImpl.h" using namespace KSVG; #include "SVGStylableImpl.lut.h" #include "ksvg_scriptinterpreter.h" #include "ksvg_bridge.h" #include "ksvg_ecma.h" SVGStylableImpl::SVGStylableImpl(SVGElementImpl *object) : m_object(object) { KSVG_EMPTY_FLAGS // View propidx.html, if you want to verify those default values (Niko) m_flags = SVG_STYLE_FLAG_NONE; // Initialize all pointers to 0 // Important! m_color = 0; m_fillColor = 0; m_stopColor = 0; m_dashArray = 0; m_dashOffset = 0; m_strokeWidth = 0; m_strokeColor = 0; m_fontFamily = 0; m_fillOpacity = 1; m_strokeOpacity = 1; m_opacity = 1; // Special case, getFontSize() could be accessed // _before_ processStyle() is called -> no default // value for font-size yet -> crash // SVGLengthImpl access it when parsing em/ex values (Niko) m_fontSize = -1; } SVGStylableImpl::~SVGStylableImpl() { if(m_strokeWidth) m_strokeWidth->deref(); if(m_fontFamily) m_fontFamily->deref(); if(m_strokeColor) m_strokeColor->deref(); if(m_fillColor) m_fillColor->deref(); if(m_color) m_color->deref(); if(m_stopColor) m_stopColor->deref(); if(m_dashOffset) m_dashOffset->deref(); if(m_dashArray) m_dashArray->deref(); } void SVGStylableImpl::processStyle() { SVGStylableImpl *parentStyle = 0; if(m_object && m_object->ownerDoc()) parentStyle = dynamic_cast<SVGStylableImpl *>(m_object->ownerDoc()->getElementFromHandle((*m_object).parentNode().handle())); // Spec: default "none" if(~m_flags & SVG_STYLE_FLAG_STROKE) { m_strokeColor = new SVGPaintImpl(m_object); m_strokeColor->ref(); SVGPaintImpl *strokeColor = 0L; if(parentStyle) strokeColor = parentStyle->getStrokeColor(); if(strokeColor) *m_strokeColor = *strokeColor; else m_strokeColor->setPaint(SVG_PAINTTYPE_NONE); } // Spec: default "black" if(~m_flags & SVG_STYLE_FLAG_FILL) { m_fillColor = new SVGPaintImpl(m_object); m_fillColor->ref(); SVGPaintImpl *fillColor = 0; if(parentStyle) fillColor = parentStyle->getFillColor(); if(fillColor) *m_fillColor = *fillColor; else m_fillColor->setRGBColor(DOM::DOMString("black")); } // Spec: no real default if(~m_flags & SVG_STYLE_FLAG_COLOR) { m_color = new SVGColorImpl(m_object); m_color->ref(); SVGColorImpl *color = 0; if(parentStyle) color = parentStyle->getColor(); if(color) *m_color = *color; } // Spec: default sRGB if(~m_flags & SVG_STYLE_FLAG_COLOR_INTERPOLATION) { if(parentStyle) m_colorInterpolation = parentStyle->getColorInterpolation(); else m_colorInterpolation = CI_SRGB; } // Spec: default "1" if(~m_flags & SVG_STYLE_FLAG_STROKE_WIDTH) { m_strokeWidth = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); m_strokeWidth->ref(); SVGAnimatedLengthImpl *strokeWidth = 0; if(parentStyle) strokeWidth = parentStyle->getStrokeWidth(); if(strokeWidth) *m_strokeWidth = *strokeWidth; else m_strokeWidth->baseVal()->setValue(1.0); } // Spec: default "4" if(~m_flags & SVG_STYLE_FLAG_STROKE_MITER_LIMIT) { if(parentStyle) m_strokeMiterlimit = parentStyle->getStrokeMiterlimit(); else m_strokeMiterlimit = 4; } // Spec: default "butt" if(~m_flags & SVG_STYLE_FLAG_STROKE_LINE_CAP) { if(parentStyle) m_capStyle = parentStyle->getCapStyle(); else m_capStyle = PATH_STROKE_CAP_BUTT; } // Spec: default "miter" if(~m_flags & SVG_STYLE_FLAG_STROKE_LINE_JOIN) { if(parentStyle) m_joinStyle = parentStyle->getJoinStyle(); else m_joinStyle = PATH_STROKE_JOIN_MITER; } // Spec: default "auto" if(~m_flags & SVG_STYLE_FLAG_CURSOR) { if(parentStyle) m_cursor = parentStyle->getCursor(); else m_cursor = CURSOR_AUTO; } // Spec: default "visiblePainted" if(~m_flags & SVG_STYLE_FLAG_POINTER_EVENTS) { if(parentStyle) m_pointerEvents = parentStyle->getPointerEvents(); else m_pointerEvents = PE_VISIBLE_PAINTED; } // Spec: default "0" if(~m_flags & SVG_STYLE_FLAG_STROKE_DASH_OFFSET) { m_dashOffset = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); m_dashOffset->ref(); SVGAnimatedLengthImpl *dashOffset = 0; if(parentStyle) dashOffset = parentStyle->getDashOffset(); if(dashOffset) *m_dashOffset = *dashOffset; else m_dashOffset->baseVal()->setValue(0); } // Spec: default "none" -> 0 == empty dash array if(~m_flags & SVG_STYLE_FLAG_STROKE_DASH_ARRAY) { SVGAnimatedLengthListImpl *dashArray = 0; if(parentStyle) dashArray = parentStyle->getDashArray(); if(dashArray) { if (!m_dashArray) { m_dashArray = new SVGAnimatedLengthListImpl(); m_dashArray->ref(); } *m_dashArray = *dashArray; } else m_dashArray = 0; } // Spec: default "1" -> 1 == Not opaque if(~m_flags & SVG_STYLE_FLAG_FILL_OPACITY) { if(parentStyle) m_fillOpacity = parentStyle->getFillOpacity(); else m_fillOpacity = 1; } if(~m_flags & SVG_STYLE_FLAG_STROKE_OPACITY) { if(parentStyle) m_strokeOpacity = parentStyle->getStrokeOpacity(); else m_strokeOpacity = 1; } // Fake group opacity by multiplying by our parent's group opacity if(~m_flags & SVG_STYLE_FLAG_OPACITY) { if(parentStyle) m_opacity = parentStyle->getOpacity(); else m_opacity = 1; } else if(parentStyle) m_opacity *= parentStyle->getOpacity(); if(~m_flags & SVG_STYLE_FLAG_CLIP_PATH) m_clipPath = ""; if(~m_flags & SVG_STYLE_FLAG_MASK) m_mask = ""; // Spec: default "nonzero" if(~m_flags & SVG_STYLE_FLAG_FILL_RULE) { if(parentStyle) m_fillRule = parentStyle->getFillRule(); else m_fillRule = RULE_NONZERO; } if(~m_flags & SVG_STYLE_FLAG_CLIP_RULE) { if(parentStyle) m_clipRule = parentStyle->getClipRule(); else m_clipRule = RULE_NONZERO; } // Spec: default "hidden" if(~m_flags & SVG_STYLE_FLAG_OVERFLOW) { if(parentStyle) m_overflow = parentStyle->getOverflow(); else m_overflow = false; } // We are not really, spec compatible here, we just // define a bool, to indicate wheter an element should // be rendered or not. if(~m_flags & SVG_STYLE_FLAG_DISPLAY) m_display = true; if(~m_flags & SVG_STYLE_FLAG_VISIBILITY) { if(parentStyle) m_visible = parentStyle->getVisible(); else m_visible = true; } // Spec: default "medium" if(~m_flags & SVG_STYLE_FLAG_FONT_SIZE) { if(parentStyle) m_fontSize = parentStyle->getFontSize(); else m_fontSize = fontSizeForText("medium"); } // Spec: default "depends on user agent" -> "Arial" for SVG if(~m_flags & SVG_STYLE_FLAG_FONT_FAMILY) { if(!m_fontFamily) { m_fontFamily = new SVGStringListImpl(); m_fontFamily->ref(); } SVGStringListImpl *fontFamily = 0; if(parentStyle) fontFamily = parentStyle->getFontFamily(); if(fontFamily) *m_fontFamily = *fontFamily; else { SharedString *string = new SharedString("Arial"); string->ref(); m_fontFamily->appendItem(string); } } // Spec: default "normal" if(~m_flags & SVG_STYLE_FLAG_FONT_STYLE) { if(parentStyle) m_fontStyle = parentStyle->getFontStyle(); else m_fontStyle = FSNORMAL; } // Spec: default "normal" if(~m_flags & SVG_STYLE_FLAG_FONT_WEIGHT) { if(parentStyle) m_fontWeight = parentStyle->getFontWeight(); else m_fontWeight = "normal"; } // Spec: default "start" if(~m_flags & SVG_STYLE_FLAG_TEXT_ANCHOR) { if(parentStyle) m_textAnchor = parentStyle->getTextAnchor(); else m_textAnchor = TASTART; } // Spec: default "LTR" if(~m_flags & SVG_STYLE_FLAG_TEXT_DIRECTION) { if(parentStyle) m_textDirection = parentStyle->getTextDirection(); else m_textDirection = LTR; } // Spec: default "none" if(~m_flags & SVG_STYLE_FLAG_TEXT_DECORATION) { if(parentStyle) m_textDecoration = parentStyle->getTextDecoration(); else m_textDecoration = TDNONE; } // Spec: default "baseline" if(~m_flags & SVG_STYLE_FLAG_BASELINE_SHIFT) { if(parentStyle) m_baselineShift = parentStyle->getBaselineShift(); else m_baselineShift = "baseline"; } // Spec: default "lr-tb", FIXME if(~m_flags & SVG_STYLE_FLAG_TEXT_WRITING_MODE) { if(parentStyle) m_textWritingMode = parentStyle->getTextWritingMode(); else m_textWritingMode = LR; } // Spec: default "normal" if(~m_flags & SVG_STYLE_FLAG_TEXT_UNICODE_BIDI) { if(parentStyle) m_textUnicodeBidi = parentStyle->getTextUnicodeBidi(); else m_textUnicodeBidi = UBNORMAL; } // Spec: default "auto" if(~m_flags & SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL) { if(parentStyle) m_glyphOrientationVertical = parentStyle->getGlyphOrientationVertical(); else m_glyphOrientationVertical = "auto"; } // Spec: default "auto" if(~m_flags & SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL) { if(parentStyle) m_glyphOrientationHorizontal = parentStyle->getGlyphOrientationHorizontal(); else m_glyphOrientationHorizontal = "auto"; } // Spec: default "normal" if(~m_flags & SVG_STYLE_FLAG_LETTER_SPACING) { if(parentStyle) m_letterSpacing = parentStyle->getLetterSpacing(); else m_letterSpacing = "normal"; } // Spec: default "normal" if(~m_flags & SVG_STYLE_FLAG_WORD_SPACING) { if(parentStyle) m_wordSpacing = parentStyle->getWordSpacing(); else m_wordSpacing = "normal"; } // Spec: default "black" if(~m_flags & SVG_STYLE_FLAG_STOP) { m_stopColor = new SVGColorImpl(m_object); m_stopColor->ref(); m_stopColor->setRGBColor(DOM::DOMString("black")); } // Spec: default "none" if(~m_flags & SVG_STYLE_FLAG_MARKER_START) { if(parentStyle) m_startMarker = parentStyle->getStartMarker(); else m_startMarker = QString::null; } // Spec: default "none" if(~m_flags & SVG_STYLE_FLAG_MARKER_MID) { if(parentStyle) m_midMarker = parentStyle->getMidMarker(); else m_midMarker = QString::null; } // Spec: default "none" if(~m_flags & SVG_STYLE_FLAG_MARKER_END) { if(parentStyle) m_endMarker = parentStyle->getEndMarker(); else m_endMarker = QString::null; } } bool SVGStylableImpl::isStroked() const { if(!m_strokeColor) return false; return m_strokeColor->paintType() != SVG_PAINTTYPE_UNKNOWN && m_strokeColor->paintType() != SVG_PAINTTYPE_NONE && m_strokeColor->paintType() != SVG_PAINTTYPE_URI_NONE; } bool SVGStylableImpl::isFilled() const { if(!m_fillColor) return false; return m_fillColor->paintType() != SVG_PAINTTYPE_UNKNOWN && m_fillColor->paintType() != SVG_PAINTTYPE_NONE && m_fillColor->paintType() != SVG_PAINTTYPE_URI_NONE; } QString SVGStylableImpl::extractUrlId(const QString &url) { QString id; if(url.startsWith("url(#")) { int idstart = url.find("#") + 1; id = url.mid(idstart, url.length() - idstart - 1); } else id = url; return id; } void SVGStylableImpl::setMarkers(const QString &marker) { setStartMarker(marker); setMidMarker(marker); setEndMarker(marker); } void SVGStylableImpl::setStartMarker(const QString &startMarker) { if(startMarker.startsWith("url(#")) { int idstart = startMarker.find("#") + 1; m_startMarker = startMarker.mid(idstart, startMarker.length() - idstart - 1); } else if(startMarker == "none") m_startMarker = QString::null; } void SVGStylableImpl::setMidMarker(const QString &midMarker) { if(midMarker.startsWith("url(#")) { int idstart = midMarker.find("#") + 1; m_midMarker = midMarker.mid(idstart, midMarker.length() - idstart - 1); } else if(midMarker == "none") m_midMarker = QString::null; } void SVGStylableImpl::setEndMarker(const QString &endMarker) { if(endMarker.startsWith("url(#")) { int idstart = endMarker.find("#") + 1; m_endMarker = endMarker.mid(idstart, endMarker.length() - idstart - 1); } else if(endMarker == "none") m_endMarker = QString::null; } bool SVGStylableImpl::hasMarkers() const { return !m_startMarker.isEmpty() || !m_midMarker.isEmpty() || !m_endMarker.isEmpty(); } void SVGStylableImpl::setPaint(const QString ¶m, SVGPaintImpl *svgPaint) { if(param.stripWhiteSpace() == "none") svgPaint->setPaint(SVG_PAINTTYPE_NONE, DOM::DOMString(""), DOM::DOMString("")); else if(SVGURIReferenceImpl::isUrl(param)) svgPaint->setUri(SVGURIReferenceImpl::getTarget(param)); else setColor(param, svgPaint); } void SVGStylableImpl::setColor(const QString ¶m, SVGColorImpl *svgColor) { if(param.stripWhiteSpace().startsWith("#")) { if(param.contains("icc-color")) { QString first = param.left(7); QString last = param.right(param.length() - 8); svgColor->setRGBColorICCColor(first, last); } else { QColor color; color.setNamedColor(param.stripWhiteSpace()); svgColor->setRGBColor(color); } } else if(param.stripWhiteSpace().startsWith("rgb(")) { QString parse = param.stripWhiteSpace(); QStringList colors = QStringList::split(',', parse); QString r = colors[0].right((colors[0].length() - 4)); QString g = colors[1]; QString b = colors[2].left((colors[2].length() - 1)); if(r.contains("%")) { r = r.left(r.length() - 1); r = QString::number(int((double(255 * r.toDouble()) / 100.0))); } if(g.contains("%")) { g = g.left(g.length() - 1); g = QString::number(int((double(255 * g.toDouble()) / 100.0))); } if(b.contains("%")) { b = b.left(b.length() - 1); b = QString::number(int((double(255 * b.toDouble()) / 100.0))); } svgColor->setRGBColor(int(r.toFloat()), int(g.toFloat()), int(b.toFloat())); } else { if(param.stripWhiteSpace().lower() == "currentcolor") svgColor->setColor(SVG_COLORTYPE_CURRENTCOLOR, DOM::DOMString(""), DOM::DOMString("")); else svgColor->setRGBColor(DOM::DOMString(param.stripWhiteSpace().lower())); } } QRect SVGStylableImpl::clip() { return QRect(); } void SVGStylableImpl::setClip(const QString &) { } float SVGStylableImpl::fontSizeForText(const QString &value) { float ret = -1; // Spec: "On a computer screen a scaling factor of 1.2 is suggested between adjacent indexes" const float factor = 1.2; // Spec: "If the 'medium' font is 12pt, the 'large' font could be 14.4pt." const float mediumFont = 12.0; if(value == "xx-small") ret = mediumFont - (3.0 * factor); else if(value == "x-small") ret = mediumFont - (2.0 * factor); else if(value == "small") ret = mediumFont - factor; else if(value == "medium") ret = mediumFont; else if(value == "large") ret = mediumFont + factor; else if(value == "x-large") ret = mediumFont + (2.0 * factor); else if(value == "xx-large") ret = mediumFont + (3.0 * factor); return ret; } // Ecma stuff /* @namespace KSVG @begin SVGStylableImpl::s_hashTable 47 className SVGStylableImpl::ClassName DontDelete|ReadOnly style SVGStylableImpl::Style DontDelete|ReadOnly stroke-width SVGStylableImpl::StrokeWidth DontDelete|ReadOnly stroke-miterlimit SVGStylableImpl::StrokeMiterlimit DontDelete|ReadOnly stroke-linecap SVGStylableImpl::StrokeLineCap DontDelete|ReadOnly stroke-linejoin SVGStylableImpl::StrokeLineJoin DontDelete|ReadOnly stroke SVGStylableImpl::Stroke DontDelete|ReadOnly fill SVGStylableImpl::Fill DontDelete|ReadOnly color SVGStylableImpl::Color DontDelete|ReadOnly stop-color SVGStylableImpl::StopColor DontDelete|ReadOnly font-size SVGStylableImpl::FontSize DontDelete|ReadOnly font-family SVGStylableImpl::FontFamily DontDelete|ReadOnly font-weight SVGStylableImpl::FontWeight DontDelete|ReadOnly font-style SVGStylableImpl::FontStyle DontDelete|ReadOnly text-decoration SVGStylableImpl::TextDecoration DontDelete|ReadOnly text-anchor SVGStylableImpl::TextAnchor DontDelete|ReadOnly direction SVGStylableImpl::Direction DontDelete|ReadOnly writing-mode SVGStylableImpl::WritingMode DontDelete|ReadOnly unicode-bidi SVGStylableImpl::UnicodeBidi DontDelete|ReadOnly opacity SVGStylableImpl::Opacity DontDelete|ReadOnly fill-opacity SVGStylableImpl::FillOpacity DontDelete|ReadOnly stroke-opacity SVGStylableImpl::StrokeOpacity DontDelete|ReadOnly clip-path SVGStylableImpl::ClipPath DontDelete|ReadOnly marker-start SVGStylableImpl::MarkerStart DontDelete|ReadOnly marker-mid SVGStylableImpl::MarkerMid DontDelete|ReadOnly marker-end SVGStylableImpl::MarkerEnd DontDelete|ReadOnly marker SVGStylableImpl::Marker DontDelete|ReadOnly cursor SVGStylableImpl::Cursor DontDelete|ReadOnly display SVGStylableImpl::Display DontDelete|ReadOnly overflow SVGStylableImpl::Overflow DontDelete|ReadOnly clip SVGStylableImpl::Clip DontDelete|ReadOnly visibility SVGStylableImpl::Visibility DontDelete|ReadOnly fill-rule SVGStylableImpl::FillRule DontDelete|ReadOnly clip-rule SVGStylableImpl::ClipRule DontDelete|ReadOnly stroke-dashoffset SVGStylableImpl::StrokeDashOffset DontDelete|ReadOnly stroke-dasharray SVGStylableImpl::StrokeDashArray DontDelete|ReadOnly color-profile SVGStylableImpl::ColorProfile DontDelete|ReadOnly baseline-shift SVGStylableImpl::BaselineShift DontDelete|ReadOnly letter-spacing SVGStylableImpl::LetterSpacing DontDelete|ReadOnly word-spacing SVGStylableImpl::WordSpacing DontDelete|ReadOnly pointer-events SVGStylableImpl::PointerEvents DontDelete|ReadOnly glyph-orientation-vertical SVGStylableImpl::GlyphOrientationVertical DontDelete|ReadOnly glyph-orientation-horizontal SVGStylableImpl::GlyphOrientationHorizontal DontDelete|ReadOnly color-interpolation SVGStylableImpl::ColorInterpolation DontDelete|ReadOnly mask SVGStylableImpl::Mask DontDelete|ReadOnly @end @namespace KSVG @begin SVGStylableImplProto::s_hashTable 2 getStyle SVGStylableImpl::GetStyle DontDelete|Function 0 @end */ KSVG_IMPLEMENT_PROTOTYPE("SVGStylable", SVGStylableImplProto, SVGStylableImplProtoFunc) Value SVGStylableImpl::getValueProperty(ExecState *, int token) const { switch(token) { //case ClassName: // return String(className().string()); case Style: return String(m_object ? m_object->DOM::Element::getAttribute("style") : ""); case Visibility: return String(m_visible ? "visible" : "hidden"); case Display: return String(m_display ? "inline" : "none"); default: kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; return Undefined(); } } void SVGStylableImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr) { // This class has just ReadOnly properties, only with the Internal flag set // it's allowed to modify those. if(!(attr & KJS::Internal)) return; QString param = value.toString(exec).qstring(); if (param.isEmpty()) return; bool redraw = false; bool inherit = (param == "inherit"); int update = -1; switch(token) { case Style: { if(!m_object) return; QStringList substyles = QStringList::split(';', param); for(QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it) { QStringList substyle = QStringList::split(':', (*it)); m_object->setAttributeInternal(substyle[0].stripWhiteSpace(), substyle[1].stripWhiteSpace()); } break; } case StrokeWidth: if(m_flags & SVG_STYLE_FLAG_STROKE_WIDTH) { redraw = true; update = UPDATE_LINEWIDTH; } if(inherit) m_flags &= ~SVG_STYLE_FLAG_STROKE_WIDTH; else { m_flags |= SVG_STYLE_FLAG_STROKE_WIDTH; if(!m_strokeWidth) { m_strokeWidth = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); m_strokeWidth->ref(); } m_strokeWidth->baseVal()->setValueAsString(param); } break; case StrokeMiterlimit: m_flags |= SVG_STYLE_FLAG_STROKE_MITER_LIMIT; if(!inherit) m_strokeMiterlimit = param.toUInt(); break; case StrokeLineCap: m_flags |= SVG_STYLE_FLAG_STROKE_LINE_CAP; if(param == "butt") m_capStyle = PATH_STROKE_CAP_BUTT; else if(param == "round") m_capStyle = PATH_STROKE_CAP_ROUND; else if(param == "square") m_capStyle = PATH_STROKE_CAP_SQUARE; break; case StrokeLineJoin: m_flags |= SVG_STYLE_FLAG_STROKE_LINE_JOIN; if(param == "miter") m_joinStyle = PATH_STROKE_JOIN_MITER; else if(param == "round") m_joinStyle = PATH_STROKE_JOIN_ROUND; else if(param == "bevel") m_joinStyle = PATH_STROKE_JOIN_BEVEL; break; case Stroke: if(m_flags & SVG_STYLE_FLAG_STROKE) redraw = true; if(inherit) m_flags &= ~SVG_STYLE_FLAG_STROKE; else { m_flags |= SVG_STYLE_FLAG_STROKE; if(!m_strokeColor) { m_strokeColor = new SVGPaintImpl(m_object); m_strokeColor->ref(); } setPaint(param, m_strokeColor); } break; case Fill: if(m_flags & SVG_STYLE_FLAG_FILL) { redraw = true; update = UPDATE_STYLE; } if(inherit) m_flags &= ~SVG_STYLE_FLAG_FILL; else { m_flags |= SVG_STYLE_FLAG_FILL; if(!m_fillColor) { m_fillColor = new SVGPaintImpl(m_object); m_fillColor->ref(); } setPaint(param, m_fillColor); } break; case Color: if(m_flags & SVG_STYLE_FLAG_COLOR) redraw = true; if(inherit) m_flags &= ~SVG_STYLE_FLAG_COLOR; else { m_flags |= SVG_STYLE_FLAG_COLOR; if(!m_color) { m_color = new SVGColorImpl(m_object); m_color->ref(); } setColor(param, m_color); } break; case StopColor: m_flags |= SVG_STYLE_FLAG_STOP; if(!m_stopColor) { m_stopColor = new SVGColorImpl(m_object); m_stopColor->ref(); } if(!inherit) setColor(param, m_stopColor); break; case ColorInterpolation: if(inherit) m_flags &= ~SVG_STYLE_FLAG_COLOR_INTERPOLATION; else { m_flags |= SVG_STYLE_FLAG_COLOR_INTERPOLATION; if(param == "auto" || param == "sRGB") m_colorInterpolation = CI_SRGB; else if(param == "linearRGB") m_colorInterpolation = CI_LINEARRGB; } break; case FontSize: { m_flags |= SVG_STYLE_FLAG_FONT_SIZE; if(!inherit) { double temp = fontSizeForText(param); if(temp != -1) // Is "absolute-size" { m_fontSize = temp; break; } SVGLengthImpl *length = SVGSVGElementImpl::createSVGLength(); length->setContext(m_object); length->setValueAsString(DOM::DOMString(param)); m_fontSize = length->value(); length->deref(); } break; } case FontFamily: m_flags |= SVG_STYLE_FLAG_FONT_FAMILY; // Hacks // #1 Replace "'" characters by "" param = param.replace('\'', QString::null); // #2 Replace "MS-Gothic" by "MS Gothic" param = param.replace("MS-Gothic", "MS Gothic"); // #3 Replace "Helvetica" by "Arial" param = param.replace("Helvetica", "Arial"); param = param.replace("helvetica", "Arial"); if(!m_fontFamily) { m_fontFamily = new SVGStringListImpl(); m_fontFamily->ref(); } if(!inherit) SVGHelperImpl::parseCommaSeperatedList(m_fontFamily, param); break; case FontWeight: m_flags |= SVG_STYLE_FLAG_FONT_WEIGHT; if(!inherit) m_fontWeight = param; break; case FontStyle: m_flags |= SVG_STYLE_FLAG_FONT_STYLE; if(param == "normal") m_fontStyle = FSNORMAL; else if(param == "italic") m_fontStyle = ITALIC; else if(param == "oblique") m_fontStyle = OBLIQUE; break; case TextDecoration: m_flags |= SVG_STYLE_FLAG_TEXT_DECORATION; if(param == "none") m_textDecoration = TDNONE; { // CSS2 allows multiple decorations m_textDecoration = TDNONE; QStringList decorations = QStringList::split(' ', param); for(QStringList::Iterator it = decorations.begin(); it != decorations.end(); ++it) { if(*it == "underline") m_textDecoration |= UNDERLINE; else if(*it == "overline") m_textDecoration |= OVERLINE; else if(*it == "line-through") m_textDecoration |= LINE_THROUGH; } } break; case TextAnchor: m_flags |= SVG_STYLE_FLAG_TEXT_ANCHOR; if(param == "start") m_textAnchor = TASTART; else if(param == "middle") m_textAnchor = TAMIDDLE; else if(param == "end") m_textAnchor = TAEND; break; case Direction: m_flags |= SVG_STYLE_FLAG_TEXT_DIRECTION; // Spec: direction is only processed when unicode-bidi // is set to bidi-override or embedded if(m_textUnicodeBidi == OVERRIDE || m_textUnicodeBidi == EMBED || m_textUnicodeBidi == UBNORMAL) { if(param == "rtl") m_textDirection = RTL; else if(param == "ltr") m_textDirection = LTR; } break; case WritingMode: m_flags |= SVG_STYLE_FLAG_TEXT_WRITING_MODE; if(param == "lr-tb" || param == "lr") m_textWritingMode = LR; else if(param == "rl-tb" || param == "rl") m_textWritingMode = RL; else if(param == "tb-lr" || param == "tb") m_textWritingMode = TB; break; case UnicodeBidi: m_flags |= SVG_STYLE_FLAG_TEXT_UNICODE_BIDI; if(param == "normal") m_textUnicodeBidi = UBNORMAL; else if(param == "embed") m_textUnicodeBidi = EMBED; else if(param == "bidi-override") m_textUnicodeBidi = OVERRIDE; break; case GlyphOrientationVertical: m_flags |= SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL; m_glyphOrientationVertical = param; break; case GlyphOrientationHorizontal: m_flags |= SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL; m_glyphOrientationHorizontal = param; break; case Opacity: m_flags |= SVG_STYLE_FLAG_OPACITY; if(!inherit) { SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_opacity); } break; case FillOpacity: m_flags |= SVG_STYLE_FLAG_FILL_OPACITY; if(!inherit) { SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_fillOpacity); } break; case StrokeOpacity: m_flags |= SVG_STYLE_FLAG_STROKE_OPACITY; if(!inherit) { SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_strokeOpacity); } break; case ClipPath: m_flags |= SVG_STYLE_FLAG_CLIP_PATH; if(!inherit) m_clipPath = extractUrlId(param); break; case Mask: m_flags |= SVG_STYLE_FLAG_MASK; if(!inherit) m_mask = extractUrlId(param); break; case MarkerStart: m_flags |= SVG_STYLE_FLAG_MARKER_START; if(!inherit) setStartMarker(param); break; case MarkerMid: m_flags |= SVG_STYLE_FLAG_MARKER_MID; if(!inherit) setMidMarker(param); break; case MarkerEnd: m_flags |= SVG_STYLE_FLAG_MARKER_END; if(!inherit) setEndMarker(param); break; case Marker: m_flags |= (SVG_STYLE_FLAG_MARKER_START | SVG_STYLE_FLAG_MARKER_MID | SVG_STYLE_FLAG_MARKER_END); if(!inherit) setMarkers(param); break; case PointerEvents: m_flags |= SVG_STYLE_FLAG_POINTER_EVENTS; if(param == "none") m_pointerEvents = PE_NONE; else if(param == "stroke") m_pointerEvents = PE_STROKE; else if(param == "fill") m_pointerEvents = PE_FILL; else if(param == "painted") m_pointerEvents = PE_PAINTED; else if(param == "visibleStroke") m_pointerEvents = PE_VISIBLE_STROKE; else if(param == "visibleFill") m_pointerEvents = PE_VISIBLE_FILL; else if(param == "visiblePainted") m_pointerEvents = PE_VISIBLE_PAINTED; else if(param == "visible") m_pointerEvents = PE_VISIBLE; else if(param == "all") m_pointerEvents = PE_ALL; break; case Cursor: m_flags |= SVG_STYLE_FLAG_CURSOR; if(param == "auto") m_cursor = CURSOR_AUTO; else if(param == "crosshair") m_cursor = CURSOR_CROSSHAIR; else if(param == "default") m_cursor = CURSOR_DEFAULT; else if(param == "pointer") m_cursor = CURSOR_POINTER; else if(param == "move") m_cursor = CURSOR_MOVE; else if(param == "e-resize") m_cursor = CURSOR_E_RESIZE; else if(param == "ne-resize") m_cursor = CURSOR_NE_RESIZE; else if(param == "nw-resize") m_cursor = CURSOR_NW_RESIZE; else if(param == "n-resize") m_cursor = CURSOR_N_RESIZE; else if(param == "se-resize") m_cursor = CURSOR_SE_RESIZE; else if(param == "sw-resize") m_cursor = CURSOR_SW_RESIZE; else if(param == "s-resize") m_cursor = CURSOR_S_RESIZE; else if(param == "w-resize") m_cursor = CURSOR_W_RESIZE; else if(param == "text") m_cursor = CURSOR_TEXT; else if(param == "wait") m_cursor = CURSOR_WAIT; else if(param == "help") m_cursor = CURSOR_HELP; break; case Display: m_flags |= SVG_STYLE_FLAG_DISPLAY; if(param == "none") m_display = false; else if(!inherit) m_display = true; break; case Overflow: m_flags |= SVG_STYLE_FLAG_OVERFLOW; if(param == "hidden" || param == "scroll") m_overflow = false; else if(!inherit) m_overflow = true; break; case Clip: m_flags |= SVG_STYLE_FLAG_CLIP_PATH; if(!inherit) setClip(param); break; case Visibility: if(m_flags & SVG_STYLE_FLAG_VISIBILITY) redraw = true; if(inherit) m_flags &= ~SVG_STYLE_FLAG_COLOR; else { m_flags |= SVG_STYLE_FLAG_VISIBILITY; if(param == "visible") m_visible = true; else if(!inherit) m_visible = false; // Just a quick fix for the script-* files (Niko) // Any better solution?? update = UPDATE_TRANSFORM; redraw = true; } SVGHelperImpl::applyContainer<SVGStylableImpl>(this, Visibility, param); break; case FillRule: m_flags |= SVG_STYLE_FLAG_FILL_RULE; if(!inherit) m_fillRule = (param == "evenodd" ? RULE_EVENODD : RULE_NONZERO); break; case ClipRule: m_flags |= SVG_STYLE_FLAG_CLIP_RULE; if(!inherit) m_clipRule = (param == "evenodd" ? RULE_EVENODD : RULE_NONZERO); break; case StrokeDashOffset: m_flags |= SVG_STYLE_FLAG_STROKE_DASH_OFFSET; if(!m_dashOffset) { m_dashOffset = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object); m_dashOffset->ref(); } if(!inherit) m_dashOffset->baseVal()->setValueAsString(param); break; case StrokeDashArray: { m_flags |= SVG_STYLE_FLAG_STROKE_DASH_ARRAY; if(!m_dashArray) { m_dashArray = new SVGAnimatedLengthListImpl(); m_dashArray->ref(); } else m_dashArray->baseVal()->clear(); if(param != "none" && !inherit) SVGHelperImpl::parseLengthList(m_dashArray, param); break; } case ColorProfile: { m_flags |= SVG_STYLE_FLAG_COLOR_PROFILE; if(!inherit) { if(!m_object) return; SVGColorProfileElementImpl *handle = static_cast<SVGColorProfileElementImpl *>(m_object->ownerSVGElement()->getElementById(SVGURIReferenceImpl::getTarget(param))); if(handle) SVGImageElementImpl::applyColorProfile(handle, static_cast<SVGImageElementImpl *>(this)); } break; } case BaselineShift: { m_flags |= SVG_STYLE_FLAG_BASELINE_SHIFT; if(!inherit) m_baselineShift = param; break; } case LetterSpacing: m_flags |= SVG_STYLE_FLAG_LETTER_SPACING; case WordSpacing: { if(!inherit) { if(token == WordSpacing) { m_flags |= SVG_STYLE_FLAG_WORD_SPACING; m_wordSpacing = param; } else m_letterSpacing = param; } break; } default: kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; } if(redraw) { SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(m_object); if(inherit) processStyle(); if(shape && shape->item()) { if(update > -1) shape->item()->update(static_cast<CanvasItemUpdate>(update)); else if(m_object) m_object->ownerDoc()->canvas()->invalidate(shape->item(), false); } } } Value SVGStylableImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &) { KSVG_CHECK_THIS(SVGStylableImpl) switch(id) { case SVGStylableImpl::GetStyle: return Undefined(); default: kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; break; } return Undefined(); } // vim:ts=4:noet