Example #1
0
bool SVGPathParser::parseArcToSegment()
{
    float rx;
    float ry;
    float angle;
    bool largeArc;
    bool sweep;
    FloatPoint targetPoint;
    if (!m_source.parseArcToSegment(rx, ry, angle, largeArc, sweep, targetPoint))
        return false;

    // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto") joining the endpoints.
    // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
    // If the current point and target point for the arc are identical, it should be treated as a zero length
    // path. This ensures continuity in animations.
    rx = fabsf(rx);
    ry = fabsf(ry);
    bool arcIsZeroLength = false;
    if (m_pathParsingMode == NormalizedParsing) {
        if (m_mode == RelativeCoordinates)
            arcIsZeroLength = targetPoint == FloatPoint::zero();
        else
            arcIsZeroLength = targetPoint == m_currentPoint;
    }
    if (!rx || !ry || arcIsZeroLength) {
        if (m_pathParsingMode == NormalizedParsing) {
            if (m_mode == RelativeCoordinates)
                m_currentPoint += targetPoint;
            else
                m_currentPoint = targetPoint;
            m_consumer.lineTo(m_currentPoint, AbsoluteCoordinates);
        } else
            m_consumer.lineTo(targetPoint, m_mode);
        return true;
    }

    if (m_pathParsingMode == NormalizedParsing) {
        FloatPoint point1 = m_currentPoint;
        if (m_mode == RelativeCoordinates)
            targetPoint += m_currentPoint;
        m_currentPoint = targetPoint;
        return decomposeArcToCubic(angle, rx, ry, point1, targetPoint, largeArc, sweep);
    }
    m_consumer.arcTo(rx, ry, angle, largeArc, sweep, targetPoint, m_mode);
    return true;
}
Example #2
0
void SVGPathNormalizer::emitSegment(const PathSegmentData& segment) {
  PathSegmentData normSeg = segment;

  // Convert relative points to absolute points.
  switch (segment.command) {
    case PathSegCurveToQuadraticRel:
      normSeg.point1 += m_currentPoint;
      normSeg.targetPoint += m_currentPoint;
      break;
    case PathSegCurveToCubicRel:
      normSeg.point1 += m_currentPoint;
    /* fall through */
    case PathSegCurveToCubicSmoothRel:
      normSeg.point2 += m_currentPoint;
    /* fall through */
    case PathSegMoveToRel:
    case PathSegLineToRel:
    case PathSegLineToHorizontalRel:
    case PathSegLineToVerticalRel:
    case PathSegCurveToQuadraticSmoothRel:
    case PathSegArcRel:
      normSeg.targetPoint += m_currentPoint;
      break;
    case PathSegLineToHorizontalAbs:
      normSeg.targetPoint.setY(m_currentPoint.y());
      break;
    case PathSegLineToVerticalAbs:
      normSeg.targetPoint.setX(m_currentPoint.x());
      break;
    case PathSegClosePath:
      // Reset m_currentPoint for the next path.
      normSeg.targetPoint = m_subPathPoint;
      break;
    default:
      break;
  }

  // Update command verb, handle smooth segments and convert quadratic curve
  // segments to cubics.
  switch (segment.command) {
    case PathSegMoveToRel:
    case PathSegMoveToAbs:
      m_subPathPoint = normSeg.targetPoint;
      normSeg.command = PathSegMoveToAbs;
      break;
    case PathSegLineToRel:
    case PathSegLineToAbs:
    case PathSegLineToHorizontalRel:
    case PathSegLineToHorizontalAbs:
    case PathSegLineToVerticalRel:
    case PathSegLineToVerticalAbs:
      normSeg.command = PathSegLineToAbs;
      break;
    case PathSegClosePath:
      normSeg.command = PathSegClosePath;
      break;
    case PathSegCurveToCubicSmoothRel:
    case PathSegCurveToCubicSmoothAbs:
      if (!isCubicCommand(m_lastCommand))
        normSeg.point1 = m_currentPoint;
      else
        normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint);
    /* fall through */
    case PathSegCurveToCubicRel:
    case PathSegCurveToCubicAbs:
      m_controlPoint = normSeg.point2;
      normSeg.command = PathSegCurveToCubicAbs;
      break;
    case PathSegCurveToQuadraticSmoothRel:
    case PathSegCurveToQuadraticSmoothAbs:
      if (!isQuadraticCommand(m_lastCommand))
        normSeg.point1 = m_currentPoint;
      else
        normSeg.point1 = reflectedPoint(m_currentPoint, m_controlPoint);
    /* fall through */
    case PathSegCurveToQuadraticRel:
    case PathSegCurveToQuadraticAbs:
      // Save the unmodified control point.
      m_controlPoint = normSeg.point1;
      normSeg.point1 = blendPoints(m_currentPoint, m_controlPoint);
      normSeg.point2 = blendPoints(normSeg.targetPoint, m_controlPoint);
      normSeg.command = PathSegCurveToCubicAbs;
      break;
    case PathSegArcRel:
    case PathSegArcAbs:
      if (!decomposeArcToCubic(m_currentPoint, normSeg)) {
        // On failure, emit a line segment to the target point.
        normSeg.command = PathSegLineToAbs;
      } else {
        // decomposeArcToCubic() has already emitted the normalized
        // segments, so set command to PathSegArcAbs, to skip any further
        // emit.
        normSeg.command = PathSegArcAbs;
      }
      break;
    default:
      ASSERT_NOT_REACHED();
  }

  if (normSeg.command != PathSegArcAbs)
    m_consumer->emitSegment(normSeg);

  m_currentPoint = normSeg.targetPoint;

  if (!isCubicCommand(segment.command) && !isQuadraticCommand(segment.command))
    m_controlPoint = m_currentPoint;

  m_lastCommand = segment.command;
}