Ejemplo n.º 1
0
FloatPoint Path::currentPoint() const
{
    if (hasCurrentPoint()) {
        SkPoint lastPt;
        m_path->getLastPt(&lastPt);
        return lastPt;
    }
    float quietNaN = std::numeric_limits<float>::quiet_NaN();
    return FloatPoint(quietNaN, quietNaN);
}
Ejemplo n.º 2
0
void Path::addArc(const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise)
{
    // The OpenVG spec says nothing about inf as radius or start/end angle.
    // WebKit seems to pass those (e.g. https://bugs.webkit.org/show_bug.cgi?id=16449),
    // so abort instead of risking undefined behavior.
    if (!isfinite(radius) || !isfinite(startAngle) || !isfinite(endAngle))
        return;

    // For some reason, the HTML 5 spec defines the angle as going clockwise
    // from the positive X axis instead of going standard anticlockwise.
    // So let's make it a proper angle in order to keep sanity.
    startAngle = fmod((2.0 * piDouble) - startAngle, 2.0 * piDouble);
    endAngle = fmod((2.0 * piDouble) - endAngle, 2.0 * piDouble);

    // Make it so that endAngle > startAngle. fmod() above takes care of
    // keeping the difference below 360 degrees.
    if (endAngle <= startAngle)
        endAngle += 2.0 * piDouble;

    m_path->makeCompatibleContextCurrent();

    const VGfloat angleDelta = anticlockwise
        ? (endAngle - startAngle)
        : (startAngle - endAngle + (2.0 * piDouble));

    // OpenVG uses endpoint parameterization while this method receives its
    // values in center parameterization. It lacks an ellipse rotation
    // parameter so we use 0 for that, and also the radius is only a single
    // value which makes for rh == rv. In order to convert from endpoint to
    // center parameterization, we use the formulas from the OpenVG/SVG specs:

    // (x,y) = (cos rot, -sin rot; sin rot, -cos rot) * (rh * cos angle, rv * sin angle) + (center.x, center.y)
    // rot is 0, which simplifies this a bit:
    // (x,y) = (1, 0; 0, -1) * (rh * cos angle, rv * sin angle) + (center.x, center.y)
    //       = (1 * rh * cos angle + 0 * rv * sin angle, 0 * rh * cos angle + -1 * rv * sin angle) + (center.x, center.y)
    //       = (rh * cos angle, -rv * sin angle) + (center.x, center.y)
    // (Set angle = {startAngle, endAngle} to retrieve the respective endpoints.)

    const VGfloat startX = radius * cos(startAngle) + center.x();
    const VGfloat startY = -radius * sin(startAngle) + center.y();
    const VGfloat endX = radius * cos(endAngle) + center.x();
    const VGfloat endY = -radius * sin(endAngle) + center.y();

    if (angleDelta > 2.0 * piDouble - 0.05) {
        VGUErrorCode error = vguEllipse(m_path->vgPath(),
            center.x(), center.y(), radius * 2, radius * 2);
        ASSERT(error == VGU_NO_ERROR);
    } else {
        // Fa: large arc flag, makes the difference between SCWARC_TO and
        //     LCWARC_TO, respectively SCCWARC_TO and LCCWARC_TO arcs.
        const bool largeArc = (angleDelta > piDouble);

        // Fs: sweep flag, specifying whether the arc is drawn in increasing
        //     (true) or decreasing (0) direction. No need to calculate this
        //     value, as it we already get it passed as a parameter
        //     (Fs == !anticlockwise).

        // Translate the large arc and sweep flags into an OpenVG segment
        // command. As OpenVG thinks of everything upside down, we need to
        // reverse the anticlockwise parameter in order to get the specified
        // rotation.
        const VGubyte segmentCommand = !anticlockwise
            ? (largeArc ? VG_LCCWARC_TO_ABS : VG_SCCWARC_TO_ABS)
            : (largeArc ? VG_LCWARC_TO_ABS : VG_SCWARC_TO_ABS);

        // So now, we've got all the parameters in endpoint parameterization
        // format as OpenVG requires it. Which means we can just pass it
        // like this.
        const VGubyte pathSegments[] = {
            hasCurrentPoint() ? VG_LINE_TO_ABS : VG_MOVE_TO_ABS,
            segmentCommand
        };
        const VGfloat pathData[] = {
            startX, startY,
            radius, radius, 0, endX, endY
        };

        m_path->appendPathData(2, pathSegments, pathData);
    }

    m_path->m_currentPoint.setX(endX);
    m_path->m_currentPoint.setY(endY);
}