aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/util')
-rw-r--r--src/declarative/util/qdeclarativepath.cpp661
-rw-r--r--src/declarative/util/qdeclarativepath_p.h181
-rw-r--r--src/declarative/util/qdeclarativepath_p_p.h13
-rw-r--r--src/declarative/util/qdeclarativepathinterpolator.cpp122
-rw-r--r--src/declarative/util/qdeclarativepathinterpolator_p.h100
-rw-r--r--src/declarative/util/qdeclarativesvgparser.cpp633
-rw-r--r--src/declarative/util/qdeclarativesvgparser_p.h60
-rw-r--r--src/declarative/util/util.pri8
8 files changed, 1708 insertions, 70 deletions
diff --git a/src/declarative/util/qdeclarativepath.cpp b/src/declarative/util/qdeclarativepath.cpp
index 34752b5242..57387f5ddd 100644
--- a/src/declarative/util/qdeclarativepath.cpp
+++ b/src/declarative/util/qdeclarativepath.cpp
@@ -41,6 +41,7 @@
#include "private/qdeclarativepath_p.h"
#include "private/qdeclarativepath_p_p.h"
+#include "private/qdeclarativesvgparser_p.h"
#include <QSet>
#include <QTime>
@@ -97,35 +98,47 @@ QDeclarativePath::~QDeclarativePath()
qreal QDeclarativePath::startX() const
{
Q_D(const QDeclarativePath);
- return d->startX;
+ return d->startX.isNull ? 0 : d->startX.value;
}
void QDeclarativePath::setStartX(qreal x)
{
Q_D(QDeclarativePath);
- if (qFuzzyCompare(x, d->startX))
+ if (d->startX.isValid() && qFuzzyCompare(x, d->startX))
return;
d->startX = x;
emit startXChanged();
processPath();
}
+bool QDeclarativePath::hasStartX() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startX.isValid();
+}
+
qreal QDeclarativePath::startY() const
{
Q_D(const QDeclarativePath);
- return d->startY;
+ return d->startY.isNull ? 0 : d->startY.value;
}
void QDeclarativePath::setStartY(qreal y)
{
Q_D(QDeclarativePath);
- if (qFuzzyCompare(y, d->startY))
+ if (d->startY.isValid() && qFuzzyCompare(y, d->startY))
return;
d->startY = y;
emit startYChanged();
processPath();
}
+bool QDeclarativePath::hasStartY() const
+{
+ Q_D(const QDeclarativePath);
+ return d->startY.isValid();
+}
+
/*!
\qmlproperty bool QtQuick2::Path::closed
This property holds whether the start and end of the path are identical.
@@ -163,6 +176,11 @@ QDeclarativeListProperty<QDeclarativePathElement> QDeclarativePath::pathElements
void QDeclarativePath::interpolate(int idx, const QString &name, qreal value)
{
Q_D(QDeclarativePath);
+ interpolate(d->_attributePoints, idx, name, value);
+}
+
+void QDeclarativePath::interpolate(QList<AttributePoint> &attributePoints, int idx, const QString &name, qreal value)
+{
if (!idx)
return;
@@ -170,7 +188,7 @@ void QDeclarativePath::interpolate(int idx, const QString &name, qreal value)
qreal lastPercent = 0;
int search = idx - 1;
while(search >= 0) {
- const AttributePoint &point = d->_attributePoints.at(search);
+ const AttributePoint &point = attributePoints.at(search);
if (point.values.contains(name)) {
lastValue = point.values.value(name);
lastPercent = point.origpercent;
@@ -181,10 +199,10 @@ void QDeclarativePath::interpolate(int idx, const QString &name, qreal value)
++search;
- const AttributePoint &curPoint = d->_attributePoints.at(idx);
+ const AttributePoint &curPoint = attributePoints.at(idx);
for (int ii = search; ii < idx; ++ii) {
- AttributePoint &point = d->_attributePoints[ii];
+ AttributePoint &point = attributePoints[ii];
qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
point.values.insert(name, val);
@@ -208,6 +226,22 @@ void QDeclarativePath::endpoint(const QString &name)
}
}
+void QDeclarativePath::endpoint(QList<AttributePoint> &attributePoints, const QString &name)
+{
+ const AttributePoint &first = attributePoints.first();
+ qreal val = first.values.value(name);
+ for (int ii = attributePoints.count() - 1; ii >= 0; ii--) {
+ const AttributePoint &point = attributePoints.at(ii);
+ if (point.values.contains(name)) {
+ for (int jj = ii + 1; jj < attributePoints.count(); ++jj) {
+ AttributePoint &setPoint = attributePoints[jj];
+ setPoint.values.insert(name, val);
+ }
+ return;
+ }
+ }
+}
+
static QString percentString(QStringLiteral("_qfx_percent"));
void QDeclarativePath::processPath()
@@ -218,42 +252,64 @@ void QDeclarativePath::processPath()
return;
d->_pointCache.clear();
- d->_attributePoints.clear();
- d->_path = QPainterPath();
+ d->prevBez.isValid = false;
+
+ d->_path = createPath(QPointF(), QPointF(), d->_attributes, d->pathLength, d->_attributePoints, &d->closed);
+
+ emit changed();
+}
+
+QPainterPath QDeclarativePath::createPath(const QPointF &startPoint, const QPointF &endPoint, const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints, bool *closed)
+{
+ Q_D(QDeclarativePath);
+
+ pathLength = 0;
+ attributePoints.clear();
+
+ if (!d->componentComplete)
+ return QPainterPath();
+
+ QPainterPath path;
AttributePoint first;
- for (int ii = 0; ii < d->_attributes.count(); ++ii)
- first.values[d->_attributes.at(ii)] = 0;
- d->_attributePoints << first;
+ for (int ii = 0; ii < attributes.count(); ++ii)
+ first.values[attributes.at(ii)] = 0;
+ attributePoints << first;
- d->_path.moveTo(d->startX, d->startY);
+ qreal startX = d->startX.isValid() ? d->startX.value : startPoint.x();
+ qreal startY = d->startY.isValid() ? d->startY.value : startPoint.y();
+ path.moveTo(startX, startY);
- QDeclarativeCurve *lastCurve = 0;
bool usesPercent = false;
+ int index = 0;
foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
if (QDeclarativeCurve *curve = qobject_cast<QDeclarativeCurve *>(pathElement)) {
- curve->addToPath(d->_path);
+ QDeclarativePathData data;
+ data.index = index;
+ data.endPoint = endPoint;
+ data.curves = d->_pathCurves;
+ curve->addToPath(path, data);
AttributePoint p;
- p.origpercent = d->_path.length();
- d->_attributePoints << p;
- lastCurve = curve;
+ p.origpercent = path.length();
+ attributePoints << p;
+ ++index;
} else if (QDeclarativePathAttribute *attribute = qobject_cast<QDeclarativePathAttribute *>(pathElement)) {
- AttributePoint &point = d->_attributePoints.last();
+ AttributePoint &point = attributePoints.last();
point.values[attribute->name()] = attribute->value();
- interpolate(d->_attributePoints.count() - 1, attribute->name(), attribute->value());
+ interpolate(attributePoints, attributePoints.count() - 1, attribute->name(), attribute->value());
} else if (QDeclarativePathPercent *percent = qobject_cast<QDeclarativePathPercent *>(pathElement)) {
- AttributePoint &point = d->_attributePoints.last();
+ AttributePoint &point = attributePoints.last();
point.values[percentString] = percent->value();
- interpolate(d->_attributePoints.count() - 1, percentString, percent->value());
+ interpolate(attributePoints, attributePoints.count() - 1, percentString, percent->value());
usesPercent = true;
}
}
// Fixup end points
- const AttributePoint &last = d->_attributePoints.last();
- for (int ii = 0; ii < d->_attributes.count(); ++ii) {
- if (!last.values.contains(d->_attributes.at(ii)))
- endpoint(d->_attributes.at(ii));
+ const AttributePoint &last = attributePoints.last();
+ for (int ii = 0; ii < attributes.count(); ++ii) {
+ if (!last.values.contains(attributes.at(ii)))
+ endpoint(attributePoints, attributes.at(ii));
}
if (usesPercent && !last.values.contains(percentString)) {
d->_attributePoints.last().values[percentString] = 1;
@@ -262,30 +318,34 @@ void QDeclarativePath::processPath()
// Adjust percent
- qreal length = d->_path.length();
+ qreal length = path.length();
qreal prevpercent = 0;
qreal prevorigpercent = 0;
- for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
- const AttributePoint &point = d->_attributePoints.at(ii);
+ for (int ii = 0; ii < attributePoints.count(); ++ii) {
+ const AttributePoint &point = attributePoints.at(ii);
if (point.values.contains(percentString)) { //special string for QDeclarativePathPercent
if ( ii > 0) {
- qreal scale = (d->_attributePoints[ii].origpercent/length - prevorigpercent) /
+ qreal scale = (attributePoints[ii].origpercent/length - prevorigpercent) /
(point.values.value(percentString)-prevpercent);
- d->_attributePoints[ii].scale = scale;
+ attributePoints[ii].scale = scale;
}
- d->_attributePoints[ii].origpercent /= length;
- d->_attributePoints[ii].percent = point.values.value(percentString);
- prevorigpercent = d->_attributePoints[ii].origpercent;
- prevpercent = d->_attributePoints[ii].percent;
+ attributePoints[ii].origpercent /= length;
+ attributePoints[ii].percent = point.values.value(percentString);
+ prevorigpercent = attributePoints[ii].origpercent;
+ prevpercent = attributePoints[ii].percent;
} else {
- d->_attributePoints[ii].origpercent /= length;
- d->_attributePoints[ii].percent = d->_attributePoints[ii].origpercent;
+ attributePoints[ii].origpercent /= length;
+ attributePoints[ii].percent = attributePoints[ii].origpercent;
}
}
- d->closed = lastCurve && d->startX == lastCurve->x() && d->startY == lastCurve->y();
+ if (closed) {
+ QPointF end = path.currentPosition();
+ *closed = length > 0 && startX == end.x() && startY == end.y();
+ }
+ pathLength = length;
- emit changed();
+ return path;
}
void QDeclarativePath::classBegin()
@@ -302,8 +362,11 @@ void QDeclarativePath::componentComplete()
// First gather up all the attributes
foreach (QDeclarativePathElement *pathElement, d->_pathElements) {
- if (QDeclarativePathAttribute *attribute =
- qobject_cast<QDeclarativePathAttribute *>(pathElement))
+ if (QDeclarativeCurve *curve =
+ qobject_cast<QDeclarativeCurve *>(pathElement))
+ d->_pathCurves.append(curve);
+ else if (QDeclarativePathAttribute *attribute =
+ qobject_cast<QDeclarativePathAttribute *>(pathElement))
attrs.insert(attribute->name());
}
d->_attributes = attrs.toList();
@@ -337,10 +400,10 @@ QStringList QDeclarativePath::attributes() const
return d->_attributes;
}
-static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bezLength)
+static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bezLength, bool reverse = false)
{
- const int lastElement = path.elementCount() - 1;
- for (int i=*from; i <= lastElement; ++i) {
+ const int lastElement = reverse ? 0 : path.elementCount() - 1;
+ for (int i=*from; reverse ? i >= lastElement : i <= lastElement; reverse ? --i : ++i) {
const QPainterPath::Element &e = path.elementAt(i);
switch (e.type) {
@@ -352,7 +415,7 @@ static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bez
*bezLength = line.length();
QPointF a = path.elementAt(i-1);
QPointF delta = e - a;
- *from = i+1;
+ *from = reverse ? i-1 : i+1;
return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
}
case QPainterPath::CurveToElement:
@@ -362,7 +425,7 @@ static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bez
path.elementAt(i+1),
path.elementAt(i+2));
*bezLength = b.length();
- *from = i+3;
+ *from = reverse ? i-1 : i+3;
return b;
}
default:
@@ -374,10 +437,16 @@ static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bez
return QBezier();
}
+//derivative of the equation
+static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
+{
+ return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
+}
+
void QDeclarativePath::createPointCache() const
{
Q_D(const QDeclarativePath);
- qreal pathLength = d->_path.length();
+ qreal pathLength = d->pathLength;
if (pathLength <= 0 || qIsNaN(pathLength))
return;
// more points means less jitter between items as they move along the
@@ -426,6 +495,140 @@ void QDeclarativePath::createPointCache() const
}
}
+QPointF QDeclarativePath::sequentialPointAt(qreal p, qreal *angle) const
+{
+ Q_D(const QDeclarativePath);
+ return sequentialPointAt(d->_path, d->pathLength, d->_attributePoints, d->prevBez, p, angle);
+}
+
+QPointF QDeclarativePath::sequentialPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle)
+{
+ if (!prevBez.isValid)
+ return p > .5 ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
+ forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
+
+ return p < prevBez.p ? backwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle) :
+ forwardsPointAt(path, pathLength, attributePoints, prevBez, p, angle);
+}
+
+QPointF QDeclarativePath::forwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle)
+{
+ if (pathLength <= 0 || qIsNaN(pathLength))
+ return path.pointAtPercent(0); //expensive?
+
+ const int lastElement = path.elementCount() - 1;
+ bool haveCachedBez = prevBez.isValid;
+ int currElement = haveCachedBez ? prevBez.element : 0;
+ qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
+ QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength);
+ qreal currLength = haveCachedBez ? prevBez.currLength : bezLength;
+ qreal epc = currLength / pathLength;
+
+ //find which set we are in
+ qreal prevPercent = 0;
+ qreal prevOrigPercent = 0;
+ for (int ii = 0; ii < attributePoints.count(); ++ii) {
+ qreal percent = p;
+ const AttributePoint &point = attributePoints.at(ii);
+ if (percent < point.percent || ii == attributePoints.count() - 1) {
+ qreal elementPercent = (percent - prevPercent);
+
+ qreal spc = prevOrigPercent + elementPercent * point.scale;
+
+ while (spc > epc) {
+ if (currElement > lastElement)
+ break;
+ currBez = nextBezier(path, &currElement, &bezLength);
+ /*if (bezLength == 0.0) {
+ currLength = pathLength;
+ epc = 1.0;
+ break;
+ }*/
+ currLength += bezLength;
+ epc = currLength / pathLength;
+ }
+ prevBez.element = currElement;
+ prevBez.bezLength = bezLength;
+ prevBez.currLength = currLength;
+ prevBez.bezier = currBez;
+ prevBez.p = p;
+ prevBez.isValid = true;
+
+ qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
+
+ if (angle) {
+ qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
+ qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
+ *angle = QLineF(0, 0, m1, m2).angle();
+ }
+
+ return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
+ }
+ prevOrigPercent = point.origpercent;
+ prevPercent = point.percent;
+ }
+
+ return QPointF(0,0);
+}
+
+//ideally this should be merged with forwardsPointAt
+QPointF QDeclarativePath::backwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle)
+{
+ if (pathLength <= 0 || qIsNaN(pathLength))
+ return path.pointAtPercent(0);
+
+ const int firstElement = 0;
+ bool haveCachedBez = prevBez.isValid;
+ int currElement = haveCachedBez ? prevBez.element : path.elementCount() - 1;
+ qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
+ QBezier currBez = haveCachedBez ? prevBez.bezier : nextBezier(path, &currElement, &bezLength, true /*reverse*/);
+ qreal currLength = haveCachedBez ? prevBez.currLength : pathLength;
+ qreal prevLength = currLength - bezLength;
+ qreal epc = prevLength / pathLength;
+
+ for (int ii = attributePoints.count() - 1; ii > 0; --ii) {
+ qreal percent = p;
+ const AttributePoint &point = attributePoints.at(ii);
+ const AttributePoint &prevPoint = attributePoints.at(ii-1);
+ if (percent > prevPoint.percent || ii == 1) {
+ qreal elementPercent = (percent - prevPoint.percent);
+
+ qreal spc = prevPoint.origpercent + elementPercent * point.scale;
+
+ while (spc < epc) {
+ if (currElement < firstElement)
+ break;
+ currBez = nextBezier(path, &currElement, &bezLength, true /*reverse*/);
+ /*if (bezLength == 0.0) {
+ currLength = 0;
+ epc = 0.0;
+ break;
+ }*/
+ currLength = prevLength;
+ epc = (currLength - bezLength) / pathLength;
+ }
+ prevBez.element = currElement;
+ prevBez.bezLength = bezLength;
+ prevBez.currLength = currLength;
+ prevBez.bezier = currBez;
+ prevBez.p = p;
+ prevBez.isValid = true;
+
+ qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
+
+ if (angle) {
+ qreal m1 = slopeAt(realT, currBez.x1, currBez.x2, currBez.x3, currBez.x4);
+ qreal m2 = slopeAt(realT, currBez.y1, currBez.y2, currBez.y3, currBez.y4);
+ *angle = QLineF(0, 0, m1, m2).angle();
+ }
+
+ return currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
+ }
+ }
+
+ return QPointF(0,0);
+}
+
QPointF QDeclarativePath::pointAt(qreal p) const
{
Q_D(const QDeclarativePath);
@@ -472,32 +675,80 @@ qreal QDeclarativePath::attributeAt(const QString &name, qreal percent) const
qreal QDeclarativeCurve::x() const
{
- return _x;
+ return _x.isNull ? 0 : _x.value;
}
void QDeclarativeCurve::setX(qreal x)
{
- if (_x != x) {
+ if (_x.isNull || _x != x) {
_x = x;
emit xChanged();
emit changed();
}
}
+bool QDeclarativeCurve::hasX()
+{
+ return _x.isValid();
+}
+
qreal QDeclarativeCurve::y() const
{
- return _y;
+ return _y.isNull ? 0 : _y.value;
}
void QDeclarativeCurve::setY(qreal y)
{
- if (_y != y) {
+ if (_y.isNull || _y != y) {
_y = y;
emit yChanged();
emit changed();
}
}
+bool QDeclarativeCurve::hasY()
+{
+ return _y.isValid();
+}
+
+qreal QDeclarativeCurve::relativeX() const
+{
+ return _relativeX;
+}
+
+void QDeclarativeCurve::setRelativeX(qreal x)
+{
+ if (_relativeX.isNull || _relativeX != x) {
+ _relativeX = x;
+ emit relativeXChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativeCurve::hasRelativeX()
+{
+ return _relativeX.isValid();
+}
+
+qreal QDeclarativeCurve::relativeY() const
+{
+ return _relativeY;
+}
+
+void QDeclarativeCurve::setRelativeY(qreal y)
+{
+ if (_relativeY.isNull || _relativeY != y) {
+ _relativeY = y;
+ emit relativeYChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativeCurve::hasRelativeY()
+{
+ return _relativeY.isValid();
+}
+
/****************************************************************************/
/*!
@@ -642,9 +893,17 @@ void QDeclarativePathAttribute::setValue(qreal value)
Defines the end point of the line.
*/
-void QDeclarativePathLine::addToPath(QPainterPath &path)
+inline QPointF positionForCurve(const QDeclarativePathData &data, const QPointF &prevPoint)
{
- path.lineTo(x(), y());
+ QDeclarativeCurve *curve = data.curves.at(data.index);
+ bool isEnd = data.index == data.curves.size() - 1;
+ return QPointF(curve->hasRelativeX() ? prevPoint.x() + curve->relativeX() : !isEnd || curve->hasX() ? curve->x() : data.endPoint.x(),
+ curve->hasRelativeY() ? prevPoint.y() + curve->relativeY() : !isEnd || curve->hasY() ? curve->y() : data.endPoint.y());
+}
+
+void QDeclarativePathLine::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ path.lineTo(positionForCurve(data, path.currentPosition()));
}
/****************************************************************************/
@@ -720,9 +979,50 @@ void QDeclarativePathQuad::setControlY(qreal y)
}
}
-void QDeclarativePathQuad::addToPath(QPainterPath &path)
+qreal QDeclarativePathQuad::relativeControlX() const
+{
+ return _relativeControlX;
+}
+
+void QDeclarativePathQuad::setRelativeControlX(qreal x)
+{
+ if (_relativeControlX.isNull || _relativeControlX != x) {
+ _relativeControlX = x;
+ emit relativeControlXChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathQuad::hasRelativeControlX()
+{
+ return _relativeControlX.isValid();
+}
+
+qreal QDeclarativePathQuad::relativeControlY() const
+{
+ return _relativeControlY;
+}
+
+void QDeclarativePathQuad::setRelativeControlY(qreal y)
+{
+ if (_relativeControlY.isNull || _relativeControlY != y) {
+ _relativeControlY = y;
+ emit relativeControlYChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathQuad::hasRelativeControlY()
{
- path.quadTo(controlX(), controlY(), x(), y());
+ return _relativeControlY.isValid();
+}
+
+void QDeclarativePathQuad::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ const QPointF &prevPoint = path.currentPosition();
+ QPointF controlPoint(hasRelativeControlX() ? prevPoint.x() + relativeControlX() : controlX(),
+ hasRelativeControlY() ? prevPoint.y() + relativeControlY() : controlY());
+ path.quadTo(controlPoint, positionForCurve(data, path.currentPosition()));
}
/****************************************************************************/
@@ -828,9 +1128,256 @@ void QDeclarativePathCubic::setControl2Y(qreal y)
}
}
-void QDeclarativePathCubic::addToPath(QPainterPath &path)
+qreal QDeclarativePathCubic::relativeControl1X() const
+{
+ return _relativeControl1X;
+}
+
+void QDeclarativePathCubic::setRelativeControl1X(qreal x)
+{
+ if (_relativeControl1X.isNull || _relativeControl1X != x) {
+ _relativeControl1X = x;
+ emit relativeControl1XChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl1X()
+{
+ return _relativeControl1X.isValid();
+}
+
+qreal QDeclarativePathCubic::relativeControl1Y() const
+{
+ return _relativeControl1Y;
+}
+
+void QDeclarativePathCubic::setRelativeControl1Y(qreal y)
+{
+ if (_relativeControl1Y.isNull || _relativeControl1Y != y) {
+ _relativeControl1Y = y;
+ emit relativeControl1YChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl1Y()
+{
+ return _relativeControl1Y.isValid();
+}
+
+qreal QDeclarativePathCubic::relativeControl2X() const
+{
+ return _relativeControl2X;
+}
+
+void QDeclarativePathCubic::setRelativeControl2X(qreal x)
+{
+ if (_relativeControl2X.isNull || _relativeControl2X != x) {
+ _relativeControl2X = x;
+ emit relativeControl2XChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl2X()
+{
+ return _relativeControl2X.isValid();
+}
+
+qreal QDeclarativePathCubic::relativeControl2Y() const
+{
+ return _relativeControl2Y;
+}
+
+void QDeclarativePathCubic::setRelativeControl2Y(qreal y)
+{
+ if (_relativeControl2Y.isNull || _relativeControl2Y != y) {
+ _relativeControl2Y = y;
+ emit relativeControl2YChanged();
+ emit changed();
+ }
+}
+
+bool QDeclarativePathCubic::hasRelativeControl2Y()
+{
+ return _relativeControl2Y.isValid();
+}
+
+void QDeclarativePathCubic::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ const QPointF &prevPoint = path.currentPosition();
+ QPointF controlPoint1(hasRelativeControl1X() ? prevPoint.x() + relativeControl1X() : control1X(),
+ hasRelativeControl1Y() ? prevPoint.y() + relativeControl1Y() : control1Y());
+ QPointF controlPoint2(hasRelativeControl2X() ? prevPoint.x() + relativeControl2X() : control2X(),
+ hasRelativeControl2Y() ? prevPoint.y() + relativeControl2Y() : control2Y());
+ path.cubicTo(controlPoint1, controlPoint2, positionForCurve(data, path.currentPosition()));
+}
+
+/****************************************************************************/
+
+inline QPointF previousPathPosition(const QPainterPath &path)
+{
+ int count = path.elementCount();
+ if (count < 1)
+ return QPointF();
+
+ int index = path.elementAt(count-1).type == QPainterPath::CurveToDataElement ? count - 4 : count - 2;
+ return index > -1 ? QPointF(path.elementAt(index)) : path.pointAtPercent(0);
+}
+
+void QDeclarativePathCatmullRomCurve::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ //here we convert catmull-rom spline to bezier for use in QPainterPath.
+ //basic conversion algorithm:
+ // catmull-rom points * inverse bezier matrix * catmull-rom matrix = bezier points
+ //each point in the catmull-rom spline produces a bezier endpoint + 2 control points
+ //calculations for each point use a moving window of 4 points
+ // (previous 2 points + current point + next point)
+ QPointF prevFar, prev, point, next;
+
+ //get previous points
+ int index = data.index - 1;
+ QDeclarativeCurve *curve = index == -1 ? 0 : data.curves.at(index);
+ if (qobject_cast<QDeclarativePathCatmullRomCurve*>(curve)) {
+ prev = path.currentPosition();
+ prevFar = previousPathPosition(path);
+ } else
+ prevFar = prev = path.currentPosition();
+
+ //get current point
+ point = positionForCurve(data, path.currentPosition());
+
+ //get next point
+ index = data.index + 1;
+ if (index < data.curves.count() && qobject_cast<QDeclarativePathCatmullRomCurve*>(data.curves.at(index))) {
+ QDeclarativePathData nextData;
+ nextData.index = index;
+ nextData.endPoint = data.endPoint;
+ nextData.curves = data.curves;
+ next = positionForCurve(nextData, point);
+ } else
+ next = point;
+
+ /*
+ full conversion matrix (inverse bezier * catmull-rom):
+ 0.000, 1.000, 0.000, 0.000,
+ -0.167, 1.000, 0.167, 0.000,
+ 0.000, 0.167, 1.000, -0.167,
+ 0.000, 0.000, 1.000, 0.000
+
+ conversion doesn't require full matrix multiplication,
+ so below we simplify
+ */
+ QPointF control1(prevFar.x() * qreal(-0.167) +
+ prev.x() +
+ point.x() * qreal(0.167),
+ prevFar.y() * qreal(-0.167) +
+ prev.y() +
+ point.y() * qreal(0.167));
+
+ QPointF control2(prev.x() * qreal(0.167) +
+ point.x() +
+ next.x() * qreal(-0.167),
+ prev.y() * qreal(0.167) +
+ point.y() +
+ next.y() * qreal(-0.167));
+
+ path.cubicTo(control1, control2, point);
+}
+
+/****************************************************************************/
+
+qreal QDeclarativePathArc::radiusX() const
+{
+ return _radiusX;
+}
+
+void QDeclarativePathArc::setRadiusX(qreal radius)
+{
+ if (_radiusX == radius)
+ return;
+
+ _radiusX = radius;
+ emit radiusXChanged();
+}
+
+qreal QDeclarativePathArc::radiusY() const
+{
+ return _radiusY;
+}
+
+void QDeclarativePathArc::setRadiusY(qreal radius)
+{
+ if (_radiusY == radius)
+ return;
+
+ _radiusY = radius;
+ emit radiusYChanged();
+}
+
+bool QDeclarativePathArc::useLargeArc() const
+{
+ return _useLargeArc;
+}
+
+void QDeclarativePathArc::setUseLargeArc(bool largeArc)
+{
+ if (_useLargeArc == largeArc)
+ return;
+
+ _useLargeArc = largeArc;
+ emit useLargeArcChanged();
+}
+
+QDeclarativePathArc::ArcDirection QDeclarativePathArc::direction() const
+{
+ return _direction;
+}
+
+void QDeclarativePathArc::setDirection(ArcDirection direction)
+{
+ if (_direction == direction)
+ return;
+
+ _direction = direction;
+ emit directionChanged();
+}
+
+void QDeclarativePathArc::addToPath(QPainterPath &path, const QDeclarativePathData &data)
+{
+ const QPointF &startPoint = path.currentPosition();
+ const QPointF &endPoint = positionForCurve(data, startPoint);
+ QDeclarativeSvgParser::pathArc(path,
+ _radiusX,
+ _radiusY,
+ 0, //xAxisRotation
+ _useLargeArc,
+ _direction == Clockwise ? 1 : 0,
+ endPoint.x(),
+ endPoint.y(),
+ startPoint.x(), startPoint.y());
+}
+
+/****************************************************************************/
+
+QString QDeclarativePathSvg::path() const
+{
+ return _path;
+}
+
+void QDeclarativePathSvg::setPath(const QString &path)
+{
+ if (_path == path)
+ return;
+
+ _path = path;
+ emit pathChanged();
+}
+
+void QDeclarativePathSvg::addToPath(QPainterPath &path, const QDeclarativePathData &)
{
- path.cubicTo(control1X(), control1Y(), control2X(), control2Y(), x(), y());
+ QDeclarativeSvgParser::parsePathDataFast(_path, path);
}
/****************************************************************************/
diff --git a/src/declarative/util/qdeclarativepath_p.h b/src/declarative/util/qdeclarativepath_p.h
index c8420eb996..4ce1bcf827 100644
--- a/src/declarative/util/qdeclarativepath_p.h
+++ b/src/declarative/util/qdeclarativepath_p.h
@@ -44,6 +44,9 @@
#include <qdeclarative.h>
+#include "private/qdeclarativenullablevalue_p_p.h"
+#include <private/qbezier_p.h>
+
#include <QtCore/QObject>
#include <QtGui/QPainterPath>
@@ -52,6 +55,15 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
+
+class QDeclarativeCurve;
+struct QDeclarativePathData
+{
+ int index;
+ QPointF endPoint;
+ QList<QDeclarativeCurve*> curves;
+};
+
class Q_AUTOTEST_EXPORT QDeclarativePathElement : public QObject
{
Q_OBJECT
@@ -92,24 +104,40 @@ class Q_AUTOTEST_EXPORT QDeclarativeCurve : public QDeclarativePathElement
Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(qreal relativeX READ relativeX WRITE setRelativeX NOTIFY relativeXChanged)
+ Q_PROPERTY(qreal relativeY READ relativeY WRITE setRelativeY NOTIFY relativeYChanged)
public:
- QDeclarativeCurve(QObject *parent=0) : QDeclarativePathElement(parent), _x(0), _y(0) {}
+ QDeclarativeCurve(QObject *parent=0) : QDeclarativePathElement(parent) {}
qreal x() const;
void setX(qreal x);
+ bool hasX();
qreal y() const;
void setY(qreal y);
+ bool hasY();
+
+ qreal relativeX() const;
+ void setRelativeX(qreal x);
+ bool hasRelativeX();
+
+ qreal relativeY() const;
+ void setRelativeY(qreal y);
+ bool hasRelativeY();
- virtual void addToPath(QPainterPath &) {}
+ virtual void addToPath(QPainterPath &, const QDeclarativePathData &) {}
Q_SIGNALS:
void xChanged();
void yChanged();
+ void relativeXChanged();
+ void relativeYChanged();
private:
- qreal _x;
- qreal _y;
+ QDeclarativeNullableValue<qreal> _x;
+ QDeclarativeNullableValue<qreal> _y;
+ QDeclarativeNullableValue<qreal> _relativeX;
+ QDeclarativeNullableValue<qreal> _relativeY;
};
class Q_AUTOTEST_EXPORT QDeclarativePathLine : public QDeclarativeCurve
@@ -118,7 +146,7 @@ class Q_AUTOTEST_EXPORT QDeclarativePathLine : public QDeclarativeCurve
public:
QDeclarativePathLine(QObject *parent=0) : QDeclarativeCurve(parent) {}
- void addToPath(QPainterPath &path);
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
};
class Q_AUTOTEST_EXPORT QDeclarativePathQuad : public QDeclarativeCurve
@@ -127,6 +155,8 @@ class Q_AUTOTEST_EXPORT QDeclarativePathQuad : public QDeclarativeCurve
Q_PROPERTY(qreal controlX READ controlX WRITE setControlX NOTIFY controlXChanged)
Q_PROPERTY(qreal controlY READ controlY WRITE setControlY NOTIFY controlYChanged)
+ Q_PROPERTY(qreal relativeControlX READ relativeControlX WRITE setRelativeControlX NOTIFY relativeControlXChanged)
+ Q_PROPERTY(qreal relativeControlY READ relativeControlY WRITE setRelativeControlY NOTIFY relativeControlYChanged)
public:
QDeclarativePathQuad(QObject *parent=0) : QDeclarativeCurve(parent), _controlX(0), _controlY(0) {}
@@ -136,15 +166,27 @@ public:
qreal controlY() const;
void setControlY(qreal y);
- void addToPath(QPainterPath &path);
+ qreal relativeControlX() const;
+ void setRelativeControlX(qreal x);
+ bool hasRelativeControlX();
+
+ qreal relativeControlY() const;
+ void setRelativeControlY(qreal y);
+ bool hasRelativeControlY();
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
Q_SIGNALS:
void controlXChanged();
void controlYChanged();
+ void relativeControlXChanged();
+ void relativeControlYChanged();
private:
qreal _controlX;
qreal _controlY;
+ QDeclarativeNullableValue<qreal> _relativeControlX;
+ QDeclarativeNullableValue<qreal> _relativeControlY;
};
class Q_AUTOTEST_EXPORT QDeclarativePathCubic : public QDeclarativeCurve
@@ -155,6 +197,10 @@ class Q_AUTOTEST_EXPORT QDeclarativePathCubic : public QDeclarativeCurve
Q_PROPERTY(qreal control1Y READ control1Y WRITE setControl1Y NOTIFY control1YChanged)
Q_PROPERTY(qreal control2X READ control2X WRITE setControl2X NOTIFY control2XChanged)
Q_PROPERTY(qreal control2Y READ control2Y WRITE setControl2Y NOTIFY control2YChanged)
+ Q_PROPERTY(qreal relativeControl1X READ relativeControl1X WRITE setRelativeControl1X NOTIFY relativeControl1XChanged)
+ Q_PROPERTY(qreal relativeControl1Y READ relativeControl1Y WRITE setRelativeControl1Y NOTIFY relativeControl1YChanged)
+ Q_PROPERTY(qreal relativeControl2X READ relativeControl2X WRITE setRelativeControl2X NOTIFY relativeControl2XChanged)
+ Q_PROPERTY(qreal relativeControl2Y READ relativeControl2Y WRITE setRelativeControl2Y NOTIFY relativeControl2YChanged)
public:
QDeclarativePathCubic(QObject *parent=0) : QDeclarativeCurve(parent), _control1X(0), _control1Y(0), _control2X(0), _control2Y(0) {}
@@ -170,19 +216,113 @@ public:
qreal control2Y() const;
void setControl2Y(qreal y);
- void addToPath(QPainterPath &path);
+ qreal relativeControl1X() const;
+ void setRelativeControl1X(qreal x);
+ bool hasRelativeControl1X();
+
+ qreal relativeControl1Y() const;
+ void setRelativeControl1Y(qreal y);
+ bool hasRelativeControl1Y();
+
+ qreal relativeControl2X() const;
+ void setRelativeControl2X(qreal x);
+ bool hasRelativeControl2X();
+
+ qreal relativeControl2Y() const;
+ void setRelativeControl2Y(qreal y);
+ bool hasRelativeControl2Y();
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
Q_SIGNALS:
void control1XChanged();
void control1YChanged();
void control2XChanged();
void control2YChanged();
+ void relativeControl1XChanged();
+ void relativeControl1YChanged();
+ void relativeControl2XChanged();
+ void relativeControl2YChanged();
private:
qreal _control1X;
qreal _control1Y;
qreal _control2X;
qreal _control2Y;
+ QDeclarativeNullableValue<qreal> _relativeControl1X;
+ QDeclarativeNullableValue<qreal> _relativeControl1Y;
+ QDeclarativeNullableValue<qreal> _relativeControl2X;
+ QDeclarativeNullableValue<qreal> _relativeControl2Y;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathCatmullRomCurve : public QDeclarativeCurve
+{
+ Q_OBJECT
+public:
+ QDeclarativePathCatmullRomCurve(QObject *parent=0) : QDeclarativeCurve(parent) {}
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathArc : public QDeclarativeCurve
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal radiusX READ radiusX WRITE setRadiusX NOTIFY radiusXChanged)
+ Q_PROPERTY(qreal radiusY READ radiusY WRITE setRadiusY NOTIFY radiusYChanged)
+ Q_PROPERTY(bool useLargeArc READ useLargeArc WRITE setUseLargeArc NOTIFY useLargeArcChanged)
+ Q_PROPERTY(ArcDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
+
+public:
+ QDeclarativePathArc(QObject *parent=0)
+ : QDeclarativeCurve(parent), _radiusX(0), _radiusY(0), _useLargeArc(false), _direction(Clockwise) {}
+
+ enum ArcDirection { Clockwise, Counterclockwise };
+ Q_ENUMS(ArcDirection)
+
+ qreal radiusX() const;
+ void setRadiusX(qreal);
+
+ qreal radiusY() const;
+ void setRadiusY(qreal);
+
+ bool useLargeArc() const;
+ void setUseLargeArc(bool);
+
+ ArcDirection direction() const;
+ void setDirection(ArcDirection direction);
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+
+Q_SIGNALS:
+ void radiusXChanged();
+ void radiusYChanged();
+ void useLargeArcChanged();
+ void directionChanged();
+
+private:
+ qreal _radiusX;
+ qreal _radiusY;
+ bool _useLargeArc;
+ ArcDirection _direction;
+};
+
+class Q_AUTOTEST_EXPORT QDeclarativePathSvg : public QDeclarativeCurve
+{
+ Q_OBJECT
+ Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
+public:
+ QDeclarativePathSvg(QObject *parent=0) : QDeclarativeCurve(parent) {}
+
+ QString path() const;
+ void setPath(const QString &path);
+
+ void addToPath(QPainterPath &path, const QDeclarativePathData &);
+
+Q_SIGNALS:
+ void pathChanged();
+
+private:
+ QString _path;
};
class Q_AUTOTEST_EXPORT QDeclarativePathPercent : public QDeclarativePathElement
@@ -202,6 +342,17 @@ private:
qreal _value;
};
+struct QDeclarativeCachedBezier
+{
+ QDeclarativeCachedBezier() : isValid(false) {}
+ QBezier bezier;
+ int element;
+ qreal bezLength;
+ qreal currLength;
+ qreal p;
+ bool isValid;
+};
+
class QDeclarativePathPrivate;
class Q_AUTOTEST_EXPORT QDeclarativePath : public QObject, public QDeclarativeParserStatus
{
@@ -222,9 +373,11 @@ public:
qreal startX() const;
void setStartX(qreal x);
+ bool hasStartX() const;
qreal startY() const;
void setStartY(qreal y);
+ bool hasStartY() const;
bool isClosed() const;
@@ -232,6 +385,7 @@ public:
QStringList attributes() const;
qreal attributeAt(const QString &, qreal) const;
QPointF pointAt(qreal) const;
+ QPointF sequentialPointAt(qreal p, qreal *angle = 0) const;
Q_SIGNALS:
void changed();
@@ -263,9 +417,19 @@ private:
void endpoint(const QString &name);
void createPointCache() const;
+ static void interpolate(QList<AttributePoint> &points, int idx, const QString &name, qreal value);
+ static void endpoint(QList<AttributePoint> &attributePoints, const QString &name);
+ static QPointF forwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle = 0);
+ static QPointF backwardsPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle = 0);
+
private:
Q_DISABLE_COPY(QDeclarativePath)
Q_DECLARE_PRIVATE(QDeclarativePath)
+ friend class QSGPathAnimationUpdater;
+
+public:
+ QPainterPath createPath(const QPointF &startPoint, const QPointF &endPoint, const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints, bool *closed = 0);
+ static QPointF sequentialPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QDeclarativeCachedBezier &prevBez, qreal p, qreal *angle = 0);
};
QT_END_NAMESPACE
@@ -276,6 +440,9 @@ QML_DECLARE_TYPE(QDeclarativeCurve)
QML_DECLARE_TYPE(QDeclarativePathLine)
QML_DECLARE_TYPE(QDeclarativePathQuad)
QML_DECLARE_TYPE(QDeclarativePathCubic)
+QML_DECLARE_TYPE(QDeclarativePathCatmullRomCurve)
+QML_DECLARE_TYPE(QDeclarativePathArc)
+QML_DECLARE_TYPE(QDeclarativePathSvg)
QML_DECLARE_TYPE(QDeclarativePathPercent)
QML_DECLARE_TYPE(QDeclarativePath)
diff --git a/src/declarative/util/qdeclarativepath_p_p.h b/src/declarative/util/qdeclarativepath_p_p.h
index 4e407eca35..c7313ea225 100644
--- a/src/declarative/util/qdeclarativepath_p_p.h
+++ b/src/declarative/util/qdeclarativepath_p_p.h
@@ -56,28 +56,33 @@
#include "private/qdeclarativepath_p.h"
#include <qdeclarative.h>
+#include <QtCore/QStringList>
-#include <qstringlist.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
+
class QDeclarativePathPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QDeclarativePath)
public:
- QDeclarativePathPrivate() : startX(0), startY(0), closed(false), componentComplete(true) { }
+ QDeclarativePathPrivate() : pathLength(0), closed(false), componentComplete(true) { }
QPainterPath _path;
QList<QDeclarativePathElement*> _pathElements;
mutable QVector<QPointF> _pointCache;
QList<QDeclarativePath::AttributePoint> _attributePoints;
QStringList _attributes;
- int startX;
- int startY;
+ QList<QDeclarativeCurve*> _pathCurves;
+ mutable QDeclarativeCachedBezier prevBez;
+ QDeclarativeNullableValue<qreal> startX;
+ QDeclarativeNullableValue<qreal> startY;
+ qreal pathLength;
bool closed;
bool componentComplete;
};
QT_END_NAMESPACE
+
#endif
diff --git a/src/declarative/util/qdeclarativepathinterpolator.cpp b/src/declarative/util/qdeclarativepathinterpolator.cpp
new file mode 100644
index 0000000000..db6ef155b7
--- /dev/null
+++ b/src/declarative/util/qdeclarativepathinterpolator.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativepathinterpolator_p.h"
+
+#include "private/qdeclarativepath_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDeclarativePathInterpolator::QDeclarativePathInterpolator(QObject *parent) :
+ QObject(parent), _path(0), _x(0), _y(0), _angle(0), _progress(0)
+{
+}
+
+QDeclarativePath *QDeclarativePathInterpolator::path() const
+{
+ return _path;
+}
+
+void QDeclarativePathInterpolator::setPath(QDeclarativePath *path)
+{
+ if (_path == path)
+ return;
+ if (_path)
+ disconnect(_path, SIGNAL(changed()), this, SLOT(_q_pathUpdated()));
+ _path = path;
+ connect(_path, SIGNAL(changed()), this, SLOT(_q_pathUpdated()));
+ emit pathChanged();
+}
+
+qreal QDeclarativePathInterpolator::progress() const
+{
+ return _progress;
+}
+
+void QDeclarativePathInterpolator::setProgress(qreal progress)
+{
+ if (progress == _progress)
+ return;
+ _progress = progress;
+ emit progressChanged();
+ _q_pathUpdated();
+}
+
+qreal QDeclarativePathInterpolator::x() const
+{
+ return _x;
+}
+
+qreal QDeclarativePathInterpolator::y() const
+{
+ return _y;
+}
+
+qreal QDeclarativePathInterpolator::angle() const
+{
+ return _angle;
+}
+
+void QDeclarativePathInterpolator::_q_pathUpdated()
+{
+ if (! _path)
+ return;
+
+ qreal angle = 0;
+ const QPointF pt = _path->sequentialPointAt(_progress, &angle);
+
+ if (_x != pt.x()) {
+ _x = pt.x();
+ emit xChanged();
+ }
+
+ if (_y != pt.y()) {
+ _y = pt.y();
+ emit yChanged();
+ }
+
+ if (angle != _angle) {
+ _angle = angle;
+ emit angleChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativepathinterpolator_p.h b/src/declarative/util/qdeclarativepathinterpolator_p.h
new file mode 100644
index 0000000000..cb8ccfa8fb
--- /dev/null
+++ b/src/declarative/util/qdeclarativepathinterpolator_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEPATHINTERPOLATOR_P_H
+#define QDECLARATIVEPATHINTERPOLATOR_P_H
+
+#include <qdeclarative.h>
+#include <QObject>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePath;
+class Q_AUTOTEST_EXPORT QDeclarativePathInterpolator : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativePath *path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
+ Q_PROPERTY(qreal x READ x NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y NOTIFY yChanged)
+ Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged)
+public:
+ explicit QDeclarativePathInterpolator(QObject *parent = 0);
+
+ QDeclarativePath *path() const;
+ void setPath(QDeclarativePath *path);
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ qreal x() const;
+ qreal y() const;
+ qreal angle() const;
+
+Q_SIGNALS:
+ void pathChanged();
+ void progressChanged();
+ void xChanged();
+ void yChanged();
+ void angleChanged();
+
+private Q_SLOTS:
+ void _q_pathUpdated();
+
+private:
+ QDeclarativePath *_path;
+ qreal _x;
+ qreal _y;
+ qreal _angle;
+ qreal _progress;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativePathInterpolator)
+
+QT_END_HEADER
+
+#endif // QDECLARATIVEPATHINTERPOLATOR_P_H
diff --git a/src/declarative/util/qdeclarativesvgparser.cpp b/src/declarative/util/qdeclarativesvgparser.cpp
new file mode 100644
index 0000000000..36714d7a38
--- /dev/null
+++ b/src/declarative/util/qdeclarativesvgparser.cpp
@@ -0,0 +1,633 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclaractive module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativesvgparser_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+static const double Q_PI = 3.14159265358979323846; // pi
+
+//copied from QtSvg (qsvghandler.cpp).
+Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
+// '0' is 0x30 and '9' is 0x39
+static inline bool isDigit(ushort ch)
+{
+ static quint16 magic = 0x3ff;
+ return ((ch >> 4) == 3) && (magic >> (ch & 15));
+}
+
+static qreal toDouble(const QChar *&str)
+{
+ const int maxLen = 255;//technically doubles can go til 308+ but whatever
+ char temp[maxLen+1];
+ int pos = 0;
+
+ if (*str == QLatin1Char('-')) {
+ temp[pos++] = '-';
+ ++str;
+ } else if (*str == QLatin1Char('+')) {
+ ++str;
+ }
+ while (isDigit(str->unicode()) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ if (*str == QLatin1Char('.') && pos < maxLen) {
+ temp[pos++] = '.';
+ ++str;
+ }
+ while (isDigit(str->unicode()) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ bool exponent = false;
+ if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) {
+ exponent = true;
+ temp[pos++] = 'e';
+ ++str;
+ if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ while (isDigit(str->unicode()) && pos < maxLen) {
+ temp[pos++] = str->toLatin1();
+ ++str;
+ }
+ }
+
+ temp[pos] = '\0';
+
+ qreal val;
+ if (!exponent && pos < 10) {
+ int ival = 0;
+ const char *t = temp;
+ bool neg = false;
+ if(*t == '-') {
+ neg = true;
+ ++t;
+ }
+ while(*t && *t != '.') {
+ ival *= 10;
+ ival += (*t) - '0';
+ ++t;
+ }
+ if(*t == '.') {
+ ++t;
+ int div = 1;
+ while(*t) {
+ ival *= 10;
+ ival += (*t) - '0';
+ div *= 10;
+ ++t;
+ }
+ val = ((qreal)ival)/((qreal)div);
+ } else {
+ val = ival;
+ }
+ if (neg)
+ val = -val;
+ } else {
+#if defined(Q_WS_QWS) && !defined(Q_OS_VXWORKS)
+ if(sizeof(qreal) == sizeof(float))
+ val = strtof(temp, 0);
+ else
+#endif
+ {
+ bool ok = false;
+ val = qstrtod(temp, 0, &ok);
+ }
+ }
+ return val;
+
+}
+static qreal toDouble(const QString &str, bool *ok = NULL)
+{
+ const QChar *c = str.constData();
+ qreal res = toDouble(c);
+ if (ok) {
+ *ok = ((*c) == QLatin1Char('\0'));
+ }
+ return res;
+}
+
+static qreal toDouble(const QStringRef &str, bool *ok = NULL)
+{
+ const QChar *c = str.constData();
+ qreal res = toDouble(c);
+ if (ok) {
+ *ok = (c == (str.constData() + str.length()));
+ }
+ return res;
+}
+static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points)
+{
+ while (str->isSpace())
+ ++str;
+ while (isDigit(str->unicode()) ||
+ *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
+ *str == QLatin1Char('.')) {
+
+ points.append(toDouble(str));
+
+ while (str->isSpace())
+ ++str;
+ if (*str == QLatin1Char(','))
+ ++str;
+
+ //eat the rest of space
+ while (str->isSpace())
+ ++str;
+ }
+}
+
+static void pathArcSegment(QPainterPath &path,
+ qreal xc, qreal yc,
+ qreal th0, qreal th1,
+ qreal rx, qreal ry, qreal xAxisRotation)
+{
+ qreal sinTh, cosTh;
+ qreal a00, a01, a10, a11;
+ qreal x1, y1, x2, y2, x3, y3;
+ qreal t;
+ qreal thHalf;
+
+ sinTh = qSin(xAxisRotation * (Q_PI / 180.0));
+ cosTh = qCos(xAxisRotation * (Q_PI / 180.0));
+
+ a00 = cosTh * rx;
+ a01 = -sinTh * ry;
+ a10 = sinTh * rx;
+ a11 = cosTh * ry;
+
+ thHalf = 0.5 * (th1 - th0);
+ t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf);
+ x1 = xc + qCos(th0) - t * qSin(th0);
+ y1 = yc + qSin(th0) + t * qCos(th0);
+ x3 = xc + qCos(th1);
+ y3 = yc + qSin(th1);
+ x2 = x3 + t * qSin(th1);
+ y2 = y3 - t * qCos(th1);
+
+ path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
+ a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
+ a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
+}
+
+void QDeclarativeSvgParser::pathArc(QPainterPath &path,
+ qreal rx,
+ qreal ry,
+ qreal x_axis_rotation,
+ int large_arc_flag,
+ int sweep_flag,
+ qreal x,
+ qreal y,
+ qreal curx, qreal cury)
+{
+ qreal sin_th, cos_th;
+ qreal a00, a01, a10, a11;
+ qreal x0, y0, x1, y1, xc, yc;
+ qreal d, sfactor, sfactor_sq;
+ qreal th0, th1, th_arc;
+ int i, n_segs;
+ qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
+
+ rx = qAbs(rx);
+ ry = qAbs(ry);
+
+ sin_th = qSin(x_axis_rotation * (Q_PI / 180.0));
+ cos_th = qCos(x_axis_rotation * (Q_PI / 180.0));
+
+ dx = (curx - x) / 2.0;
+ dy = (cury - y) / 2.0;
+ dx1 = cos_th * dx + sin_th * dy;
+ dy1 = -sin_th * dx + cos_th * dy;
+ Pr1 = rx * rx;
+ Pr2 = ry * ry;
+ Px = dx1 * dx1;
+ Py = dy1 * dy1;
+ /* Spec : check if radii are large enough */
+ check = Px / Pr1 + Py / Pr2;
+ if (check > 1) {
+ rx = rx * qSqrt(check);
+ ry = ry * qSqrt(check);
+ }
+
+ a00 = cos_th / rx;
+ a01 = sin_th / rx;
+ a10 = -sin_th / ry;
+ a11 = cos_th / ry;
+ x0 = a00 * curx + a01 * cury;
+ y0 = a10 * curx + a11 * cury;
+ x1 = a00 * x + a01 * y;
+ y1 = a10 * x + a11 * y;
+ /* (x0, y0) is current point in transformed coordinate space.
+ (x1, y1) is new point in transformed coordinate space.
+
+ The arc fits a unit-radius circle in this space.
+ */
+ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
+ sfactor_sq = 1.0 / d - 0.25;
+ if (sfactor_sq < 0) sfactor_sq = 0;
+ sfactor = qSqrt(sfactor_sq);
+ if (sweep_flag == large_arc_flag) sfactor = -sfactor;
+ xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
+ yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
+ /* (xc, yc) is center of the circle. */
+
+ th0 = qAtan2(y0 - yc, x0 - xc);
+ th1 = qAtan2(y1 - yc, x1 - xc);
+
+ th_arc = th1 - th0;
+ if (th_arc < 0 && sweep_flag)
+ th_arc += 2 * Q_PI;
+ else if (th_arc > 0 && !sweep_flag)
+ th_arc -= 2 * Q_PI;
+
+ n_segs = qCeil(qAbs(th_arc / (Q_PI * 0.5 + 0.001)));
+
+ for (i = 0; i < n_segs; i++) {
+ pathArcSegment(path, xc, yc,
+ th0 + i * th_arc / n_segs,
+ th0 + (i + 1) * th_arc / n_segs,
+ rx, ry, x_axis_rotation);
+ }
+}
+
+
+bool QDeclarativeSvgParser::parsePathDataFast(const QString &dataStr, QPainterPath &path)
+{
+ qreal x0 = 0, y0 = 0; // starting point
+ qreal x = 0, y = 0; // current point
+ char lastMode = 0;
+ QPointF ctrlPt;
+ const QChar *str = dataStr.constData();
+ const QChar *end = str + dataStr.size();
+
+ while (str != end) {
+ while (str->isSpace())
+ ++str;
+ QChar pathElem = *str;
+ ++str;
+ QChar endc = *end;
+ *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee
+ QVarLengthArray<qreal, 8> arg;
+ parseNumbersArray(str, arg);
+ *const_cast<QChar *>(end) = endc;
+ if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
+ arg.append(0);//dummy
+ const qreal *num = arg.constData();
+ int count = arg.count();
+ while (count > 0) {
+ qreal offsetX = x; // correction offsets
+ qreal offsetY = y; // for relative commands
+ switch (pathElem.unicode()) {
+ case 'm': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = x0 = num[0] + offsetX;
+ y = y0 = num[1] + offsetY;
+ num += 2;
+ count -= 2;
+ path.moveTo(x0, y0);
+
+ // As per 1.2 spec 8.3.2 The "moveto" commands
+ // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
+ // the subsequent pairs shall be treated as implicit 'lineto' commands.
+ pathElem = QLatin1Char('l');
+ }
+ break;
+ case 'M': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = x0 = num[0];
+ y = y0 = num[1];
+ num += 2;
+ count -= 2;
+ path.moveTo(x0, y0);
+
+ // As per 1.2 spec 8.3.2 The "moveto" commands
+ // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
+ // the subsequent pairs shall be treated as implicit 'lineto' commands.
+ pathElem = QLatin1Char('L');
+ }
+ break;
+ case 'z':
+ case 'Z': {
+ x = x0;
+ y = y0;
+ count--; // skip dummy
+ num++;
+ path.closeSubpath();
+ }
+ break;
+ case 'l': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = num[0] + offsetX;
+ y = num[1] + offsetY;
+ num += 2;
+ count -= 2;
+ path.lineTo(x, y);
+
+ }
+ break;
+ case 'L': {
+ if (count < 2) {
+ num++;
+ count--;
+ break;
+ }
+ x = num[0];
+ y = num[1];
+ num += 2;
+ count -= 2;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'h': {
+ x = num[0] + offsetX;
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'H': {
+ x = num[0];
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'v': {
+ y = num[0] + offsetY;
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'V': {
+ y = num[0];
+ num++;
+ count--;
+ path.lineTo(x, y);
+ }
+ break;
+ case 'c': {
+ if (count < 6) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1(num[0] + offsetX, num[1] + offsetY);
+ QPointF c2(num[2] + offsetX, num[3] + offsetY);
+ QPointF e(num[4] + offsetX, num[5] + offsetY);
+ num += 6;
+ count -= 6;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'C': {
+ if (count < 6) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1(num[0], num[1]);
+ QPointF c2(num[2], num[3]);
+ QPointF e(num[4], num[5]);
+ num += 6;
+ count -= 6;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 's': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1;
+ if (lastMode == 'c' || lastMode == 'C' ||
+ lastMode == 's' || lastMode == 'S')
+ c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c1 = QPointF(x, y);
+ QPointF c2(num[0] + offsetX, num[1] + offsetY);
+ QPointF e(num[2] + offsetX, num[3] + offsetY);
+ num += 4;
+ count -= 4;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'S': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c1;
+ if (lastMode == 'c' || lastMode == 'C' ||
+ lastMode == 's' || lastMode == 'S')
+ c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c1 = QPointF(x, y);
+ QPointF c2(num[0], num[1]);
+ QPointF e(num[2], num[3]);
+ num += 4;
+ count -= 4;
+ path.cubicTo(c1, c2, e);
+ ctrlPt = c2;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'q': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c(num[0] + offsetX, num[1] + offsetY);
+ QPointF e(num[2] + offsetX, num[3] + offsetY);
+ num += 4;
+ count -= 4;
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'Q': {
+ if (count < 4) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF c(num[0], num[1]);
+ QPointF e(num[2], num[3]);
+ num += 4;
+ count -= 4;
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 't': {
+ if (count < 2) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF e(num[0] + offsetX, num[1] + offsetY);
+ num += 2;
+ count -= 2;
+ QPointF c;
+ if (lastMode == 'q' || lastMode == 'Q' ||
+ lastMode == 't' || lastMode == 'T')
+ c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c = QPointF(x, y);
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'T': {
+ if (count < 2) {
+ num += count;
+ count = 0;
+ break;
+ }
+ QPointF e(num[0], num[1]);
+ num += 2;
+ count -= 2;
+ QPointF c;
+ if (lastMode == 'q' || lastMode == 'Q' ||
+ lastMode == 't' || lastMode == 'T')
+ c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+ else
+ c = QPointF(x, y);
+ path.quadTo(c, e);
+ ctrlPt = c;
+ x = e.x();
+ y = e.y();
+ break;
+ }
+ case 'a': {
+ if (count < 7) {
+ num += count;
+ count = 0;
+ break;
+ }
+ qreal rx = (*num++);
+ qreal ry = (*num++);
+ qreal xAxisRotation = (*num++);
+ qreal largeArcFlag = (*num++);
+ qreal sweepFlag = (*num++);
+ qreal ex = (*num++) + offsetX;
+ qreal ey = (*num++) + offsetY;
+ count -= 7;
+ qreal curx = x;
+ qreal cury = y;
+ pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
+ int(sweepFlag), ex, ey, curx, cury);
+
+ x = ex;
+ y = ey;
+ }
+ break;
+ case 'A': {
+ if (count < 7) {
+ num += count;
+ count = 0;
+ break;
+ }
+ qreal rx = (*num++);
+ qreal ry = (*num++);
+ qreal xAxisRotation = (*num++);
+ qreal largeArcFlag = (*num++);
+ qreal sweepFlag = (*num++);
+ qreal ex = (*num++);
+ qreal ey = (*num++);
+ count -= 7;
+ qreal curx = x;
+ qreal cury = y;
+ pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
+ int(sweepFlag), ex, ey, curx, cury);
+
+ x = ex;
+ y = ey;
+ }
+ break;
+ default:
+ return false;
+ }
+ lastMode = pathElem.toLatin1();
+ }
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativesvgparser_p.h b/src/declarative/util/qdeclarativesvgparser_p.h
new file mode 100644
index 0000000000..0d7be10761
--- /dev/null
+++ b/src/declarative/util/qdeclarativesvgparser_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclaractive module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVESVGPARSER_P_H
+#define QDECLARATIVESVGPARSER_P_H
+
+#include <QtCore/qstring.h>
+#include <QtGui/qpainterpath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QDeclarativeSvgParser
+{
+ bool parsePathDataFast(const QString &dataStr, QPainterPath &path);
+ void pathArc(QPainterPath &path, qreal rx, qreal ry, qreal x_axis_rotation,
+ int large_arc_flag, int sweep_flag, qreal x, qreal y, qreal curx,
+ qreal cury);
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVESVGPARSER_P_H
diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri
index 965acf80c6..ddd702609c 100644
--- a/src/declarative/util/util.pri
+++ b/src/declarative/util/util.pri
@@ -29,7 +29,9 @@ SOURCES += \
$$PWD/qdeclarativelistmodelworkeragent.cpp \
$$PWD/qdeclarativepath.cpp \
$$PWD/qdeclarativechangeset.cpp \
- $$PWD/qlistmodelinterface.cpp
+ $$PWD/qlistmodelinterface.cpp \
+ $$PWD/qdeclarativepathinterpolator.cpp \
+ $$PWD/qdeclarativesvgparser.cpp
HEADERS += \
$$PWD/qdeclarativeapplication_p.h \
@@ -65,7 +67,9 @@ HEADERS += \
$$PWD/qdeclarativepath_p.h \
$$PWD/qdeclarativepath_p_p.h \
$$PWD/qdeclarativechangeset_p.h \
- $$PWD/qlistmodelinterface_p.h
+ $$PWD/qlistmodelinterface_p.h \
+ $$PWD/qdeclarativepathinterpolator_p.h \
+ $$PWD/qdeclarativesvgparser_p.h
contains(QT_CONFIG, xmlpatterns) {
QT+=xmlpatterns