From 47d455dd55be855e4cc691c32f687f723d9247ee Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- ksvg/impl/SVGPathElementImpl.cc | 868 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 868 insertions(+) create mode 100644 ksvg/impl/SVGPathElementImpl.cc (limited to 'ksvg/impl/SVGPathElementImpl.cc') diff --git a/ksvg/impl/SVGPathElementImpl.cc b/ksvg/impl/SVGPathElementImpl.cc new file mode 100644 index 00000000..f34600b8 --- /dev/null +++ b/ksvg/impl/SVGPathElementImpl.cc @@ -0,0 +1,868 @@ +/* + 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 + +#include "SVGRectImpl.h" +#include "SVGPaintImpl.h" +#include "SVGPointImpl.h" +#include "SVGAngleImpl.h" +#include "SVGDocumentImpl.h" +#include "SVGSVGElementImpl.h" +#include "SVGPathSegArcImpl.h" +#include "SVGPathSegListImpl.h" +#include "SVGPathElementImpl.h" +#include "SVGPathSegLinetoImpl.h" +#include "SVGPathSegMovetoImpl.h" +#include "SVGAnimatedNumberImpl.h" +#include "SVGPathSegClosePathImpl.h" +#include "SVGPathSegCurvetoCubicImpl.h" +#include "SVGPathSegLinetoVerticalImpl.h" +#include "SVGPathSegLinetoHorizontalImpl.h" +#include "SVGPathSegCurvetoQuadraticImpl.h" +#include "SVGPathSegCurvetoCubicSmoothImpl.h" +#include "SVGPathSegCurvetoQuadraticSmoothImpl.h" + +#include "SVGPaint.h" + +#include "CanvasItem.h" +#include "KSVGCanvas.h" +#include "BezierPath.h" +#include "Point.h" + +using namespace KSVG; + +#include "SVGPathElementImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" +#include "ksvg_ecma.h" + +SVGPathElementImpl::SVGPathElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl(), SVGAnimatedPathDataImpl(), SVGPathParser() +{ + KSVG_EMPTY_FLAGS + + m_pathLength = new SVGAnimatedNumberImpl(); + m_pathLength->ref(); + + m_pathLength->setBaseVal(0); +} + +SVGPathElementImpl::~SVGPathElementImpl() +{ + pathSegList()->clear(); + + if(m_pathLength) + m_pathLength->deref(); +} + +SVGAnimatedNumberImpl *SVGPathElementImpl::pathLength() const +{ + return m_pathLength; +} + +double SVGPathElementImpl::getTotalLength() +{ + T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item); + if(path) + return path->length(); + + return 0; +} + +SVGPointImpl *SVGPathElementImpl::getPointAtLength(double distance) +{ + SVGPointImpl *ret = SVGSVGElementImpl::createSVGPoint(); + double totalDistance = getTotalLength(); + T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item); + if(path) + { + T2P::Point p; + path->pointTangentNormalAt(distance / totalDistance, &p); + ret->setX(p.x()); + ret->setY(p.y()); + } + + return ret; +} + +unsigned long SVGPathElementImpl::getPathSegAtLength(double) +{ + return 0; +} + +SVGPathSegClosePathImpl *SVGPathElementImpl::createSVGPathSegClosePath() +{ + SVGPathSegClosePathImpl *temp = new SVGPathSegClosePathImpl(); + temp->ref(); + + return temp; +} + +SVGPathSegMovetoAbsImpl *SVGPathElementImpl::createSVGPathSegMovetoAbs(double x, double y) +{ + SVGPathSegMovetoAbsImpl *temp = new SVGPathSegMovetoAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegMovetoRelImpl *SVGPathElementImpl::createSVGPathSegMovetoRel(double x, double y) +{ + SVGPathSegMovetoRelImpl *temp = new SVGPathSegMovetoRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegLinetoAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoAbs(double x, double y) +{ + SVGPathSegLinetoAbsImpl *temp = new SVGPathSegLinetoAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegLinetoRelImpl *SVGPathElementImpl::createSVGPathSegLinetoRel(double x, double y) +{ + SVGPathSegLinetoRelImpl *temp = new SVGPathSegLinetoRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegCurvetoCubicAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicAbs(double x, double y, double x1, double y1, double x2, double y2) +{ + SVGPathSegCurvetoCubicAbsImpl *temp = new SVGPathSegCurvetoCubicAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoCubicRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicRel(double x, double y, double x1, double y1, double x2, double y2) +{ + SVGPathSegCurvetoCubicRelImpl *temp = new SVGPathSegCurvetoCubicRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoQuadraticAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticAbs(double x, double y, double x1, double y1) +{ + SVGPathSegCurvetoQuadraticAbsImpl *temp = new SVGPathSegCurvetoQuadraticAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + return temp; +} + +SVGPathSegCurvetoQuadraticRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticRel(double x, double y, double x1, double y1) +{ + SVGPathSegCurvetoQuadraticRelImpl *temp = new SVGPathSegCurvetoQuadraticRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX1(x1); + temp->setY1(y1); + return temp; +} + +SVGPathSegArcAbsImpl *SVGPathElementImpl::createSVGPathSegArcAbs(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag) +{ + SVGPathSegArcAbsImpl *temp = new SVGPathSegArcAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setR1(r1); + temp->setR2(r2); + temp->setAngle(angle); + temp->setLargeArcFlag(largeArcFlag); + temp->setSweepFlag(sweepFlag); + return temp; +} + +SVGPathSegArcRelImpl *SVGPathElementImpl::createSVGPathSegArcRel(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag) +{ + SVGPathSegArcRelImpl *temp = new SVGPathSegArcRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setR1(r1); + temp->setR2(r2); + temp->setAngle(angle); + temp->setLargeArcFlag(largeArcFlag); + temp->setSweepFlag(sweepFlag); + return temp; +} + +SVGPathSegLinetoHorizontalAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoHorizontalAbs(double x) +{ + SVGPathSegLinetoHorizontalAbsImpl *temp = new SVGPathSegLinetoHorizontalAbsImpl(); + temp->ref(); + + temp->setX(x); + return temp; +} + +SVGPathSegLinetoHorizontalRelImpl *SVGPathElementImpl::createSVGPathSegLinetoHorizontalRel(double x) +{ + SVGPathSegLinetoHorizontalRelImpl *temp = new SVGPathSegLinetoHorizontalRelImpl(); + temp->ref(); + + temp->setX(x); + return temp; +} + +SVGPathSegLinetoVerticalAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoVerticalAbs(double y) +{ + SVGPathSegLinetoVerticalAbsImpl *temp = new SVGPathSegLinetoVerticalAbsImpl(); + temp->ref(); + + temp->setY(y); + return temp; +} + +SVGPathSegLinetoVerticalRelImpl *SVGPathElementImpl::createSVGPathSegLinetoVerticalRel(double y) +{ + SVGPathSegLinetoVerticalRelImpl *temp = new SVGPathSegLinetoVerticalRelImpl(); + temp->ref(); + + temp->setY(y); + return temp; +} + +SVGPathSegCurvetoCubicSmoothAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicSmoothAbs(double x, double y, double x2, double y2) +{ + SVGPathSegCurvetoCubicSmoothAbsImpl *temp = new SVGPathSegCurvetoCubicSmoothAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoCubicSmoothRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicSmoothRel(double x, double y, double x2, double y2) +{ + SVGPathSegCurvetoCubicSmoothRelImpl *temp = new SVGPathSegCurvetoCubicSmoothRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + temp->setX2(x2); + temp->setY2(y2); + return temp; +} + +SVGPathSegCurvetoQuadraticSmoothAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticSmoothAbs(double x, double y) +{ + SVGPathSegCurvetoQuadraticSmoothAbsImpl *temp = new SVGPathSegCurvetoQuadraticSmoothAbsImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +SVGPathSegCurvetoQuadraticSmoothRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticSmoothRel(double x, double y) +{ + SVGPathSegCurvetoQuadraticSmoothRelImpl *temp = new SVGPathSegCurvetoQuadraticSmoothRelImpl(); + temp->ref(); + + temp->setX(x); + temp->setY(y); + return temp; +} + +void SVGPathElementImpl::svgMoveTo(double x1, double y1, bool, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegMovetoAbs(x1, y1)); + else + pathSegList()->appendItem(createSVGPathSegMovetoRel(x1, y1)); +} + +void SVGPathElementImpl::svgLineTo(double x1, double y1, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegLinetoAbs(x1, y1)); + else + pathSegList()->appendItem(createSVGPathSegLinetoRel(x1, y1)); +} + +void SVGPathElementImpl::svgLineToHorizontal(double x, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegLinetoHorizontalAbs(x)); + else + pathSegList()->appendItem(createSVGPathSegLinetoHorizontalRel(x)); +} + +void SVGPathElementImpl::svgLineToVertical(double y, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegLinetoVerticalAbs(y)); + else + pathSegList()->appendItem(createSVGPathSegLinetoVerticalRel(y)); +} + +void SVGPathElementImpl::svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoCubicRel(x, y, x1, y1, x2, y2)); +} + +void SVGPathElementImpl::svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoCubicSmoothAbs(x2, y2, x, y)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoCubicSmoothRel(x2, y2, x, y)); +} + +void SVGPathElementImpl::svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticAbs(x1, y1, x, y)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticRel(x1, y1, x, y)); +} + +void SVGPathElementImpl::svgCurveToQuadraticSmooth(double x, double y, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticSmoothAbs(x, y)); + else + pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticSmoothRel(x, y)); +} + +void SVGPathElementImpl::svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs) +{ + if(abs) + pathSegList()->appendItem(createSVGPathSegArcAbs(x, y, r1, r2, angle, largeArcFlag, sweepFlag)); + else + pathSegList()->appendItem(createSVGPathSegArcRel(x, y, r1, r2, angle, largeArcFlag, sweepFlag)); +} + +void SVGPathElementImpl::svgClosePath() +{ + pathSegList()->appendItem(createSVGPathSegClosePath()); +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathElementImpl::s_hashTable 3 + d SVGPathElementImpl::D DontDelete|ReadOnly + pathLength SVGPathElementImpl::PathLength DontDelete|ReadOnly +@end +@namespace KSVG +@begin SVGPathElementImplProto::s_hashTable 23 + getTotalLength SVGPathElementImpl::GetTotalLength DontDelete|Function 0 + getPointAtLength SVGPathElementImpl::GetPointAtLength DontDelete|Function 1 + getPathSegAtLength SVGPathElementImpl::GetPathSegAtLength DontDelete|Function 1 + createSVGPathSegClosePath SVGPathElementImpl::CreateSVGPathSegClosePath DontDelete|Function 0 + createSVGPathSegMovetoAbs SVGPathElementImpl::CreateSVGPathSegMovetoAbs DontDelete|Function 2 + createSVGPathSegMovetoRel SVGPathElementImpl::CreateSVGPathSegMovetoRel DontDelete|Function 2 + createSVGPathSegLinetoAbs SVGPathElementImpl::CreateSVGPathSegLinetoAbs DontDelete|Function 2 + createSVGPathSegLinetoRel SVGPathElementImpl::CreateSVGPathSegLinetoRel DontDelete|Function 2 + createSVGPathSegArcAbs SVGPathElementImpl::CreateSVGPathSegArcAbs DontDelete|Function 7 + createSVGPathSegArcRel SVGPathElementImpl::CreateSVGPathSegArcRel DontDelete|Function 7 + createSVGPathSegCurvetoCubicAbs SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs DontDelete|Function 6 + createSVGPathSegCurvetoCubicRel SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel DontDelete|Function 6 + createSVGPathSegCurvetoQuadraticAbs SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs DontDelete|Function 4 + createSVGPathSegCurvetoQuadraticRel SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel DontDelete|Function 4 + createSVGPathSegLinetoHorizontalAbs SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs DontDelete|Function 1 + createSVGPathSegLinetoHorizontalRel SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel DontDelete|Function 1 + createSVGPathSegLinetoVerticalAbs SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs DontDelete|Function 1 + createSVGPathSegLinetoVerticalRel SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel DontDelete|Function 1 + createSVGPathSegCurvetoCubicAbs SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs DontDelete|Function 4 + createSVGPathSegCurvetoCubicRel SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel DontDelete|Function 4 + createSVGPathSegCurvetoQuadraticAbs SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs DontDelete|Function 2 + createSVGPathSegCurvetoQuadraticRel SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel DontDelete|Function 2 +@end +*/ + +KSVG_IMPLEMENT_PROTOTYPE("SVGPathElementImpl", SVGPathElementImplProto, SVGPathElementImplProtoFunc) + +Value SVGPathElementImpl::getValueProperty(ExecState *exec, int token) const +{ + //KSVG_CHECK_ATTRIBUTE + + switch(token) + { + case PathLength: + return m_pathLength->cache(exec); + case D: +// if(!attributeMode) + { + QString d; + unsigned int nrSegs = pathSegList()->numberOfItems(); + SVGPathSegImpl *curseg = 0; + for(unsigned int i = 0; i < nrSegs; i++) + { + curseg = pathSegList()->getItem(i); + if(curseg) + d += curseg->toString() + " "; + } + return String(d); + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathElementImpl::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; + + switch(token) + { + case D: + { + pathSegList()->clear(); + QString d = value.toString(exec).qstring(); + parseSVG(d, false); + if(hasMarkers()) + m_markerData = MarkerData(pathSegList()); + break; + } + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +Value SVGPathElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args) +{ + KSVG_CHECK_THIS(SVGPathElementImpl) + + switch(id) + { + case SVGPathElementImpl::GetTotalLength: + return Number(obj->getTotalLength()); + case SVGPathElementImpl::GetPointAtLength: + return obj->getPointAtLength(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::GetPathSegAtLength: + return Number(obj->getPathSegAtLength(args[0].toNumber(exec))); + case SVGPathElementImpl::CreateSVGPathSegClosePath: + return obj->createSVGPathSegClosePath()->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegMovetoAbs: + return obj->createSVGPathSegMovetoAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegMovetoRel: + return obj->createSVGPathSegMovetoRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoAbs: + return obj->createSVGPathSegLinetoAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoRel: + return obj->createSVGPathSegLinetoRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs: + return obj->createSVGPathSegCurvetoCubicAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel: + return obj->createSVGPathSegCurvetoCubicRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs: + return obj->createSVGPathSegCurvetoQuadraticAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel: + return obj->createSVGPathSegCurvetoQuadraticRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegArcAbs: + return obj->createSVGPathSegArcAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toBoolean(exec), args[6].toBoolean(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegArcRel: + return obj->createSVGPathSegArcRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toBoolean(exec), args[6].toBoolean(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs: + return obj->createSVGPathSegLinetoHorizontalAbs(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel: + return obj->createSVGPathSegLinetoHorizontalRel(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs: + return obj->createSVGPathSegLinetoVerticalAbs(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel: + return obj->createSVGPathSegLinetoVerticalRel(args[0].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicSmoothAbs: + return obj->createSVGPathSegCurvetoCubicSmoothAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicSmoothRel: + return obj->createSVGPathSegCurvetoCubicSmoothRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticSmoothAbs: + return obj->createSVGPathSegCurvetoQuadraticSmoothAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticSmoothRel: + return obj->createSVGPathSegCurvetoQuadraticSmoothRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec); + default: + kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl; + break; + } + + return Undefined(); +} + +SVGRectImpl *SVGPathElementImpl::getBBox() +{ + SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect(); + + if(m_item) + { + T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item); + if(path) + { + T2P::Point topLeft; + T2P::Point bottomRight; + + path->boundingBox(&topLeft, &bottomRight); + + ret->setX(topLeft.x()); + ret->setY(topLeft.y()); + ret->setWidth(bottomRight.x() - topLeft.x()); + ret->setHeight(bottomRight.y() - topLeft.y()); + } + } + return ret; +} + +void SVGPathElementImpl::createItem(KSVGCanvas *c) +{ + if(!c) + c = ownerDoc()->canvas(); + + if(!m_item) + { + // TODO : this is a quick fix for this problem: + // d attribute encountered before marker attributes. + // Try to process the attributes in the right order, ie. + // d attr processing should be last. + if(hasMarkers() && m_markerData.numMarkers() == 0) + m_markerData = MarkerData(pathSegList()); + m_item = c->createPath(this); + c->insert(m_item); + } +} + +SVGPathElementImpl::MarkerData::MarkerData(SVGPathSegListImpl *path) +{ + unsigned int numSegments = path->numberOfItems(); + double curx = 0; + double cury = 0; + int currentSubpathStartIndex = -1; + double previousQuadraticX1 = 0; + double previousQuadraticY1 = 0; + double previousCubicX2 = 0; + double previousCubicY2 = 0; + + QValueVector pathSegmentData(numSegments); + + for(unsigned int i = 0; i < numSegments; i++) + { + SVGPathSegImpl *segment = path->getItem(i); + struct SegmentData data; + + data.type = segment->pathSegType(); + + if(segment->pathSegType() == PATHSEG_MOVETO_ABS || segment->pathSegType() == PATHSEG_MOVETO_REL) + { + if(currentSubpathStartIndex >= 0) + { + // Finish the previous subpath. + for(unsigned int j = currentSubpathStartIndex; j < i; j++) + { + pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex; + pathSegmentData[j].subpathEndIndex = i - 1; + pathSegmentData[j].subpathIsClosed = false; + } + } + + currentSubpathStartIndex = i; + } + else if(segment->pathSegType() == PATHSEG_CLOSEPATH) + { + if(currentSubpathStartIndex >= 0) + { + SVGPathSegClosePathImpl *s = static_cast(segment); + + s->setX(pathSegmentData[currentSubpathStartIndex].startx + pathSegmentData[currentSubpathStartIndex].dx); + s->setY(pathSegmentData[currentSubpathStartIndex].starty + pathSegmentData[currentSubpathStartIndex].dy); + + for(unsigned int j = currentSubpathStartIndex; j < i; j++) + { + pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex; + pathSegmentData[j].subpathEndIndex = i; + pathSegmentData[j].subpathIsClosed = true; + } + + data.subpathStartIndex = currentSubpathStartIndex; + data.subpathEndIndex = i; + data.subpathIsClosed = true; + } + + currentSubpathStartIndex = i + 1; + } + + switch(segment->pathSegType()) + { + case PATHSEG_CURVETO_CUBIC_ABS: + { + SVGPathSegCurvetoCubicAbsImpl *s = static_cast(segment); + previousCubicX2 = s->x2(); + previousCubicY2 = s->y2(); + break; + } + case PATHSEG_CURVETO_CUBIC_REL: + { + SVGPathSegCurvetoCubicRelImpl *s = static_cast(segment); + previousCubicX2 = curx + s->x2(); + previousCubicY2 = cury + s->y2(); + break; + } + case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + { + SVGPathSegCurvetoCubicSmoothAbsImpl *s = static_cast(segment); + s->setPreviousX2(previousCubicX2); + s->setPreviousY2(previousCubicY2); + previousCubicX2 = s->x2(); + previousCubicY2 = s->y2(); + break; + } + case PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + { + SVGPathSegCurvetoCubicSmoothRelImpl *s = static_cast(segment); + s->setPreviousAbsX2(previousCubicX2); + s->setPreviousAbsY2(previousCubicY2); + previousCubicX2 = curx + s->x2(); + previousCubicY2 = cury + s->y2(); + break; + } + case PATHSEG_CURVETO_QUADRATIC_ABS: + { + SVGPathSegCurvetoQuadraticAbsImpl *s = static_cast(segment); + previousQuadraticX1 = s->x1(); + previousQuadraticY1 = s->y1(); + break; + } + case PATHSEG_CURVETO_QUADRATIC_REL: + { + SVGPathSegCurvetoQuadraticRelImpl *s = static_cast(segment); + previousQuadraticX1 = curx + s->x1(); + previousQuadraticY1 = cury + s->y1(); + break; + } + case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + { + SVGPathSegCurvetoQuadraticSmoothAbsImpl *s = static_cast(segment); + s->setPreviousX1(previousQuadraticX1); + s->setPreviousY1(previousQuadraticY1); + previousQuadraticX1 = s->x1(curx); + previousQuadraticY1 = s->y1(cury); + break; + } + case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + { + SVGPathSegCurvetoQuadraticSmoothRelImpl *s = static_cast(segment); + s->setPreviousAbsX1(previousQuadraticX1); + s->setPreviousAbsY1(previousQuadraticY1); + previousQuadraticX1 = s->absX1(curx); + previousQuadraticY1 = s->absY1(cury); + break; + } + default: + previousCubicX2 = curx; + previousCubicY2 = cury; + previousQuadraticX1 = curx; + previousQuadraticY1 = cury; + break; + } + + data.startx = curx; + data.starty = cury; + + segment->getDeltasAndSlopes(curx, cury, &data.dx, &data.dy, &data.startSlope, &data.endSlope); + + pathSegmentData[i] = data; + + curx += data.dx; + cury += data.dy; + } + + if(currentSubpathStartIndex >= 0) + { + // Finish the previous subpath. + for(unsigned int j = currentSubpathStartIndex; j < numSegments; j++) + { + pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex; + pathSegmentData[j].subpathEndIndex = numSegments - 1; + pathSegmentData[j].subpathIsClosed = false; + } + } + + m_markers.resize(numSegments); + + for(unsigned int i = 0; i < numSegments; i++) + { + struct Marker marker; + + marker.x = pathSegmentData[i].startx + pathSegmentData[i].dx; + marker.y = pathSegmentData[i].starty + pathSegmentData[i].dy; + + double inSlope; + double outSlope; + bool haveInSlope = false; + bool haveOutSlope = false; + + if(pathSegmentData[i].subpathStartIndex == i && pathSegmentData[i].subpathIsClosed) + { + // Spec: For closed subpaths, the marker for the initial vertex uses the end direction + // of the corresponding closepath for its incoming slope and the first segment's + // start slope for its outgoing slope. + haveInSlope = getEndSlope(pathSegmentData, pathSegmentData[i].subpathEndIndex, &inSlope); + haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope); + } + else if(pathSegmentData[i].type == PATHSEG_CLOSEPATH) + { + haveInSlope = getEndSlope(pathSegmentData, i, &inSlope); + + // Spec: If the segment following a closepath is other than a moveto, the marker + // for the closepath uses the following segment's start direction as its + // outgoing direction. + if(i + 1 < numSegments && (pathSegmentData[i + 1].type != PATHSEG_MOVETO_ABS && pathSegmentData[i + 1].type != PATHSEG_MOVETO_REL)) + haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope); + else + haveOutSlope = getStartSlope(pathSegmentData, pathSegmentData[i].subpathStartIndex, &outSlope); + } + else + { + haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope); + haveInSlope = getEndSlope(pathSegmentData, i, &inSlope); + } + + if(!haveInSlope && !haveOutSlope) + { + outSlope = 0; + inSlope = 0; + } + else if(haveInSlope && !haveOutSlope) + outSlope = inSlope; + else if(!haveInSlope && haveOutSlope) + inSlope = outSlope; + + double bisector = SVGAngleImpl::shortestArcBisector(inSlope, outSlope); + marker.angle = bisector; + + m_markers[i] = marker; + } +} + +bool SVGPathElementImpl::MarkerData::getStartSlope(QValueVector segments, unsigned int i, double *pStartSlope) +{ + if(i > segments.count() - 1 || segments[i].type == PATHSEG_MOVETO_ABS || segments[i].type == PATHSEG_MOVETO_REL) + return false; + else + { + const double epsilon = DBL_EPSILON; + + if(fabs(segments[i].dx) > epsilon || fabs(segments[i].dy) > epsilon) + { + *pStartSlope = segments[i].startSlope; + return true; + } + else + { + int subpathStartIndex = segments[i].subpathStartIndex; + + for(int j = i - 1; j >= subpathStartIndex; j--) + { + if(segments[j].type == PATHSEG_MOVETO_ABS || segments[j].type == PATHSEG_MOVETO_REL) + return false; + + if(fabs(segments[j].dx) > epsilon || fabs(segments[j].dy) > epsilon) + { + *pStartSlope = segments[j].endSlope; + return true; + } + } + + return false; + } + } +} + +bool SVGPathElementImpl::MarkerData::getEndSlope(QValueVector segments, unsigned int i, double *pEndSlope) +{ + if(i > segments.count() - 1 || segments[i].type == PATHSEG_MOVETO_ABS || segments[i].type == PATHSEG_MOVETO_REL) + return false; + else + { + const double epsilon = DBL_EPSILON; + + if(fabs(segments[i].dx) > epsilon || fabs(segments[i].dy) > epsilon) + { + *pEndSlope = segments[i].endSlope; + return true; + } + else + { + int subpathEndIndex = segments[i].subpathEndIndex; + + for(int j = i + 1; j <= subpathEndIndex; j++) + { + if(segments[j].type == PATHSEG_MOVETO_ABS || segments[j].type == PATHSEG_MOVETO_REL) + return false; + + if(fabs(segments[j].dx) > epsilon || fabs(segments[j].dy) > epsilon) + { + *pEndSlope = segments[j].startSlope; + return true; + } + } + + return false; + } + } +} + +// vim:ts=4:noet -- cgit v1.2.1