Exemple #1
0
bool SvgParser::parseGradient(const KoXmlElement &e, const KoXmlElement &referencedBy)
{
    // IMPROVEMENTS:
    // - Store the parsed colorstops in some sort of a cache so they don't need to be parsed again.
    // - A gradient inherits attributes it does not have from the referencing gradient.
    // - Gradients with no color stops have no fill or stroke.
    // - Gradients with one color stop have a solid color.

    SvgGraphicsContext *gc = m_context.currentGC();
    if (!gc)
        return false;

    SvgGradientHelper gradhelper;

    if (e.hasAttribute("xlink:href")) {
        QString href = e.attribute("xlink:href").mid(1);
        if (! href.isEmpty()) {
            // copy the referenced gradient if found
            SvgGradientHelper *pGrad = findGradient(href);
            if (pGrad)
                gradhelper = *pGrad;
        } else {
            //gc->fillType = SvgGraphicsContext::None; // <--- TODO Fill OR Stroke are none
            return false;
        }
    }

    // Use the gradient that is referencing, or if there isn't one, the original gradient.
    KoXmlElement b;
    if (!referencedBy.isNull())
        b = referencedBy;
    else
        b = e;

    QString gradientId = b.attribute("id");

    if (! gradientId.isEmpty()) {
        // check if we have this gradient already parsed
        // copy existing gradient if it exists
        if (m_gradients.find(gradientId) != m_gradients.end())
            gradhelper.copyGradient(m_gradients[ gradientId ].gradient());
    }

    if (b.attribute("gradientUnits") == "userSpaceOnUse")
        gradhelper.setGradientUnits(SvgGradientHelper::UserSpaceOnUse);

    // parse color prop
    QColor c = gc->currentColor;

    if (!b.attribute("color").isEmpty()) {
        m_context.styleParser().parseColor(c, b.attribute("color"));
    } else {
        // try style attr
        QString style = b.attribute("style").simplified();
        const QStringList substyles = style.split(';', QString::SkipEmptyParts);
        for (QStringList::ConstIterator it = substyles.begin(); it != substyles.end(); ++it) {
            QStringList substyle = it->split(':');
            QString command = substyle[0].trimmed();
            QString params  = substyle[1].trimmed();
            if (command == "color")
                m_context.styleParser().parseColor(c, params);
        }
    }
    gc->currentColor = c;

    if (b.tagName() == "linearGradient") {
        QLinearGradient *g = new QLinearGradient();
        if (gradhelper.gradientUnits() == SvgGradientHelper::ObjectBoundingBox) {
            g->setCoordinateMode(QGradient::ObjectBoundingMode);
            g->setStart(QPointF(SvgUtil::fromPercentage(b.attribute("x1", "0%")),
                                SvgUtil::fromPercentage(b.attribute("y1", "0%"))));
            g->setFinalStop(QPointF(SvgUtil::fromPercentage(b.attribute("x2", "100%")),
                                    SvgUtil::fromPercentage(b.attribute("y2", "0%"))));
        } else {
            g->setStart(QPointF(SvgUtil::fromUserSpace(b.attribute("x1").toDouble()),
                                SvgUtil::fromUserSpace(b.attribute("y1").toDouble())));
            g->setFinalStop(QPointF(SvgUtil::fromUserSpace(b.attribute("x2").toDouble()),
                                    SvgUtil::fromUserSpace(b.attribute("y2").toDouble())));
        }
        // preserve color stops
        if (gradhelper.gradient())
            g->setStops(gradhelper.gradient()->stops());
        gradhelper.setGradient(g);
    } else if (b.tagName() == "radialGradient") {
        QRadialGradient *g = new QRadialGradient();
        if (gradhelper.gradientUnits() == SvgGradientHelper::ObjectBoundingBox) {
            g->setCoordinateMode(QGradient::ObjectBoundingMode);
            g->setCenter(QPointF(SvgUtil::fromPercentage(b.attribute("cx", "50%")),
                                 SvgUtil::fromPercentage(b.attribute("cy", "50%"))));
            g->setRadius(SvgUtil::fromPercentage(b.attribute("r", "50%")));
            g->setFocalPoint(QPointF(SvgUtil::fromPercentage(b.attribute("fx", "50%")),
                                     SvgUtil::fromPercentage(b.attribute("fy", "50%"))));
        } else {
            g->setCenter(QPointF(SvgUtil::fromUserSpace(b.attribute("cx").toDouble()),
                                 SvgUtil::fromUserSpace(b.attribute("cy").toDouble())));
            g->setFocalPoint(QPointF(SvgUtil::fromUserSpace(b.attribute("fx").toDouble()),
                                     SvgUtil::fromUserSpace(b.attribute("fy").toDouble())));
            g->setRadius(SvgUtil::fromUserSpace(b.attribute("r").toDouble()));
        }
        // preserve color stops
        if (gradhelper.gradient())
            g->setStops(gradhelper.gradient()->stops());
        gradhelper.setGradient(g);
    } else {
        return false;
    }

    // handle spread method
    QString spreadMethod = b.attribute("spreadMethod");
    if (!spreadMethod.isEmpty()) {
        if (spreadMethod == "reflect")
            gradhelper.gradient()->setSpread(QGradient::ReflectSpread);
        else if (spreadMethod == "repeat")
            gradhelper.gradient()->setSpread(QGradient::RepeatSpread);
        else
            gradhelper.gradient()->setSpread(QGradient::PadSpread);
    } else
        gradhelper.gradient()->setSpread(QGradient::PadSpread);

    // Parse the color stops. The referencing gradient does not have colorstops,
    // so use the stops from the gradient it references to (e in this case and not b)
    m_context.styleParser().parseColorStops(gradhelper.gradient(), e);
    gradhelper.setTransform(SvgUtil::parseTransform(b.attribute("gradientTransform")));
    m_gradients.insert(gradientId, gradhelper);

    return true;
}