/* 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 #include #include #include "CanvasItem.h" #include "SVGHelperImpl.h" #include "SVGDocumentImpl.h" #include "SVGSVGElementImpl.h" #include "SVGStringListImpl.h" #include "SVGURIReferenceImpl.h" #include "SVGAnimationElementImpl.h" using namespace KSVG; #include "SVGAnimationElementImpl.lut.h" #include "ksvg_bridge.h" #include "ksvg_ecma.h" SVGAnimationElementImpl::SVGAnimationElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGTestsImpl(), SVGExternalResourcesRequiredImpl() { KSVG_EMPTY_FLAGS m_connected = false; m_targetElement = 0; m_values = new SVGStringListImpl(); m_keyTimes= new SVGStringListImpl(); m_keySplines = new SVGStringListImpl(); m_fill = REMOVE; m_additive = REPLACE; m_accumulate = ACCUMULATE_NONE; } SVGAnimationElementImpl::~SVGAnimationElementImpl() { if(m_targetElement) m_targetElement->deref(); } SVGElementImpl *SVGAnimationElementImpl::targetElement() const { if(!m_targetElement) { SVGAnimationElementImpl *modify = const_cast(this); if(!m_href.isEmpty()) modify->setTargetElement(ownerDoc()->getElementByIdRecursive(ownerSVGElement(), SVGURIReferenceImpl::getTarget(m_href))); else if(!parentNode().isNull()) modify->setTargetElement(ownerDoc()->getElementFromHandle(parentNode().handle())); } return m_targetElement; } double SVGAnimationElementImpl::parseClockValue(const TQString &data) const { TQString parse = data.stripWhiteSpace(); TQString debugOutput = "parseClockValue(" + parse + ") -> "; if(parse == "indefinite") // Saves some time... return -1; double result; int doublePointOne = parse.find(':'); int doublePointTwo = parse.find(':', doublePointOne + 1); if(doublePointOne != -1 && doublePointTwo != -1) // Spec: "Full clock values" { unsigned int hours = parse.mid(0, 2).toUInt(); unsigned int minutes = parse.mid(3, 2).toUInt(); unsigned int seconds = parse.mid(6, 2).toUInt(); unsigned int milliseconds = 0; result = (3600 * hours) + (60 * minutes) + seconds; if(parse.find('.') != -1) { TQString temp = parse.mid(9, 2); milliseconds = temp.toUInt(); result += (milliseconds * (1 / pow(10.0, temp.length()))); } } else if(doublePointOne != -1 && doublePointTwo == -1) // Spec: "Partial clock values" { unsigned int minutes = parse.mid(0, 2).toUInt(); unsigned int seconds = parse.mid(3, 2).toUInt(); unsigned int milliseconds = 0; result = (60 * minutes) + seconds; if(parse.find('.') != -1) { TQString temp = parse.mid(6, 2); milliseconds = temp.toUInt(); result += (milliseconds * (1 / pow(10.0, temp.length()))); } } else // Spec: "Timecount values" { int dotPosition = parse.find('.'); if(parse.endsWith("h")) { if(dotPosition == -1) result = parse.mid(0, parse.length() - 1).toUInt() * 3600; else { result = parse.mid(0, dotPosition).toUInt() * 3600; TQString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 2); result += (3600.0 * temp.toUInt()) * (1 / pow(10.0, temp.length())); } } else if(parse.endsWith("min")) { if(dotPosition == -1) result = parse.mid(0, parse.length() - 3).toUInt() * 60; else { result = parse.mid(0, dotPosition).toUInt() * 60; TQString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 4); result += (60.0 * temp.toUInt()) * (1 / pow(10.0, temp.length())); } } else if(parse.endsWith("ms")) { if(dotPosition == -1) result = parse.mid(0, parse.length() - 2).toUInt() / 1000.0; else { result = parse.mid(0, dotPosition).toUInt() / 1000.0; TQString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 3); result += (temp.toUInt() / 1000.0) * (1 / pow(10.0, temp.length())); } } else if(parse.endsWith("s")) { if(dotPosition == -1) result = parse.mid(0, parse.length() - 1).toUInt(); else { result = parse.mid(0, dotPosition).toUInt(); TQString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 2); result += temp.toUInt() * (1 / pow(10.0, temp.length())); } } else result = parse.toDouble(); } kdDebug() << debugOutput << result << endl; return result; } /* @namespace KSVG @begin SVGAnimationElementImpl::s_hashTable 23 targetElement SVGAnimationElementImpl::TargetElement DontDelete|ReadOnly href SVGAnimationElementImpl::Href DontDelete|ReadOnly additive SVGAnimationElementImpl::Additive DontDelete|ReadOnly accumulate SVGAnimationElementImpl::Accumulate DontDelete|ReadOnly attributeName SVGAnimationElementImpl::AttributeName DontDelete|ReadOnly attributeType SVGAnimationElementImpl::AttributeType DontDelete|ReadOnly calcMode SVGAnimationElementImpl::CalcMode DontDelete|ReadOnly values SVGAnimationElementImpl::Values DontDelete|ReadOnly keyTimes SVGAnimationElementImpl::KeyTimes DontDelete|ReadOnly keySplines SVGAnimationElementImpl::KeySplines DontDelete|ReadOnly from SVGAnimationElementImpl::From DontDelete|ReadOnly to SVGAnimationElementImpl::To DontDelete|ReadOnly by SVGAnimationElementImpl::By DontDelete|ReadOnly begin SVGAnimationElementImpl::Begin DontDelete|ReadOnly dur SVGAnimationElementImpl::Dur DontDelete|ReadOnly end SVGAnimationElementImpl::End DontDelete|ReadOnly min SVGAnimationElementImpl::Min DontDelete|ReadOnly max SVGAnimationElementImpl::Max DontDelete|ReadOnly restart SVGAnimationElementImpl::Restart DontDelete|ReadOnly repeatCount SVGAnimationElementImpl::RepeatCount DontDelete|ReadOnly repeatDur SVGAnimationElementImpl::RepeatDur DontDelete|ReadOnly fill SVGAnimationElementImpl::Fill DontDelete|ReadOnly @end @namespace KSVG @begin SVGAnimationElementImplProto::s_hashTable 5 getStartTime SVGAnimationElementImpl::GetStartTime DontDelete|Function 0 getCurrentTime SVGAnimationElementImpl::GetCurrentTime DontDelete|Function 0 getSimpleDuration SVGAnimationElementImpl::GetSimpleDuration DontDelete|Function 0 @end */ KSVG_IMPLEMENT_PROTOTYPE("SVGAnimationElement",SVGAnimationElementImplProto,SVGAnimationElementImplProtoFunc) Value SVGAnimationElementImpl::getValueProperty(ExecState *exec, int token) const { switch(token) { case TargetElement: return m_targetElement->cache(exec); default: kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; return Undefined(); } } void SVGAnimationElementImpl::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; TQString val = value.toString(exec).qstring(); switch(token) { case Href: m_href = val; break; case Additive: m_additive = (val == "sum") ? SUM : REPLACE; break; case Accumulate: m_accumulate = (val == "sum") ? ACCUMULATE_SUM : ACCUMULATE_NONE; break; case AttributeName: m_attributeName = val; break; case AttributeType: if(val == "css") m_attributeType = CSS; else if(val == "xml") m_attributeType = XML; else m_attributeType = AUTO; break; case CalcMode: // FIXME: See spec for default values!!! if(val == "discrete") m_calcMode = DISCRETE; else if(val == "linear") m_calcMode = LINEAR; else if(val == "spline") m_calcMode = SPLINE; else if(val == "paced") m_calcMode = PACED; break; case Values: SVGHelperImpl::parseSemicolonSeperatedList(m_values, val); break; case KeyTimes: SVGHelperImpl::parseSemicolonSeperatedList(m_keyTimes, val); break; case KeySplines: SVGHelperImpl::parseSemicolonSeperatedList(m_keySplines, val); break; case From: m_from = val; break; case To: m_to = val; break; case By: m_by = val; break; case Begin: case End: { // Create list SVGStringListImpl *temp = new SVGStringListImpl(); temp->ref(); // Feed data into list SVGHelperImpl::parseSemicolonSeperatedList(temp, val); // Parse data for(unsigned int i = 0; i < temp->numberOfItems(); i++) { TQString current = temp->getItem(i)->string(); if(current.startsWith("accessKey")) { // Register keyDownEventListener for the character TQString character = current.mid(current.length() - 2, 1); kdDebug() << "ACCESSKEY CHARACTER " << character << endl; } else if(current.startsWith("wallclock")) { int firstBrace = current.find("("); int secondBrace = current.find(")"); TQString wallclockValue = current.mid(firstBrace + 1, secondBrace - firstBrace - 2); kdDebug() << "WALLCLOCK VALUE " << wallclockValue << endl; } else if(current.contains(".")) { int dotPosition = current.find("."); TQString element = current.mid(0, dotPosition); TQString clockValue; if(current.contains("begin")) clockValue = current.mid(dotPosition + 6); else if(current.contains("end")) clockValue = current.mid(dotPosition + 4); else if(current.contains("repeat")) clockValue = current.mid(dotPosition + 7); else // DOM2 Event Reference { int plusMinusPosition = -1; if(current.contains("+")) plusMinusPosition = current.find("+"); else if(current.contains("-")) plusMinusPosition = current.find("-"); TQString event = current.mid(dotPosition + 1, plusMinusPosition - dotPosition - 1); clockValue = current.mid(dotPosition + event.length() + 1); kdDebug() << "EVENT " << event << endl; } kdDebug() << "ELEMENT " << element << " CLOCKVALUE " << clockValue << endl; } else { if(token == Begin) m_begin = parseClockValue(current); else m_end = parseClockValue(current); } } temp->deref(); break; } case Dur: m_duration = parseClockValue(val); break; // case Min: // case Max: case Restart: if(val == "whenNotActive") m_restart = WHENNOTACTIVE; else if(val == "never") m_restart = NEVER; else m_restart = ALWAYS; break; case RepeatCount: m_repeatCount = val; break; case RepeatDur: m_repeatDur = val; break; case Fill: m_fill = (val == "freeze") ? FREEZE : REMOVE; break; default: kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; } } Value SVGAnimationElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &) { KSVG_CHECK_THIS(SVGAnimationElementImpl) switch(id) { case SVGAnimationElementImpl::GetStartTime: return Number(obj->getStartTime()); case SVGAnimationElementImpl::GetCurrentTime: return Number(obj->getCurrentTime()); case SVGAnimationElementImpl::GetSimpleDuration: return Number(obj->getSimpleDuration()); default: kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; break; } return Undefined(); } void SVGAnimationElementImpl::setAttributes() { SVGElementImpl::setAttributes(); // Spec: Default value is "replace" if(KSVG_TOKEN_NOT_PARSED(Additive)) KSVG_SET_ALT_ATTRIBUTE(Additive, "replace") // Spec: Default value is "none" if(KSVG_TOKEN_NOT_PARSED(Accumulate)) KSVG_SET_ALT_ATTRIBUTE(Accumulate, "none") // Spec: Default value is "always" if(KSVG_TOKEN_NOT_PARSED(Restart)) KSVG_SET_ALT_ATTRIBUTE(Restart, "always") } void SVGAnimationElementImpl::setTargetElement(SVGElementImpl *target) { if(m_targetElement) m_targetElement->deref(); m_targetElement = target; m_targetElement->ref(); } void SVGAnimationElementImpl::applyAttribute(const TQString &name, const TQString &value) { SVGElementImpl *target = targetElement(); if(!target) { kdDebug() << k_funcinfo << " name: " << name << " value: " << value << " NO TARGET ELEMENT!" << endl; return; } // The only two cases I can imagine, where combining is needed (Niko) bool combine = (name == "style" || name == "transform"); if(!combine) target->setAttributeInternal(name, value); else { kdDebug() << "TODO COMBINE: " << value << " NAME " << name << endl; } } double SVGAnimationElementImpl::getStartTime() const { return m_begin; } double SVGAnimationElementImpl::getCurrentTime() const { return 0.0; } double SVGAnimationElementImpl::getSimpleDuration() const { return m_duration; } // vim:ts=4:noet