180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2006 The Android Open Source Project
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include <ctype.h>
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkDrawPath.h"
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkParse.h"
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkPoint.h"
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkUtils.h"
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define QUADRATIC_APPROXIMATION 1
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if QUADRATIC_APPROXIMATION
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru////////////////////////////////////////////////////////////////////////////////////
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//functions to approximate a cubic using two quadratics
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//      midPt sets the first argument to be the midpoint of the other two
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//      it is used by quadApprox
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b)
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY));
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru//      quadApprox - makes an approximation, which we hope is faster
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //divide the cubic up into two cubics, then convert them into quadratics
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //define our points
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint c,j,k,l,m,n,o,p,q, mid;
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPath.getLastPt(&c);
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(j, p0, c);
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(k, p0, p1);
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(l, p1, p2);
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(o, j, k);
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(p, k, l);
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(q, o, p);
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //compute the first half
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY));
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY));
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(mid,m,n);
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPath.quadTo(mid,q);
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    c = q;
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //compute the second half
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY));
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY));
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    midPt(mid,m,n);
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPath.quadTo(mid,p2);
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline bool is_between(int c, int min, int max)
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return (unsigned)(c - min) <= (unsigned)(max - min);
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline bool is_ws(int c)
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return is_between(c, 1, 32);
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline bool is_digit(int c)
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return is_between(c, '0', '9');
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline bool is_sep(int c)
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return is_ws(c) || c == ',';
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const char* skip_ws(const char str[])
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(str);
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (is_ws(*str))
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        str++;
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return str;
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const char* skip_sep(const char str[])
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(str);
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    while (is_sep(*str))
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        str++;
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return str;
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const char* find_points(const char str[], SkPoint value[], int count,
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru     bool isRelative, SkPoint* relative)
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    str = SkParse::FindScalars(str, &value[0].fX, count * 2);
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (isRelative) {
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        for (int index = 0; index < count; index++) {
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            value[index].fX += relative->fX;
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            value[index].fY += relative->fY;
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return str;
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const char* find_scalar(const char str[], SkScalar* value,
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool isRelative, SkScalar relative)
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru{
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    str = SkParse::FindScalar(str, value);
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (isRelative)
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *value += relative;
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return str;
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkDrawPath::parseSVG() {
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPath.reset();
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const char* data = d.c_str();
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint f = {0, 0};
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint c = {0, 0};
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint lastc = {0, 0};
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint points[3];
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    char op = '\0';
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    char previousOp = '\0';
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool relative = false;
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        data = skip_ws(data);
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (data[0] == '\0')
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            break;
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        char ch = data[0];
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (is_digit(ch) || ch == '-' || ch == '+') {
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (op == '\0')
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                return;
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        else {
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            op = ch;
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            relative = false;
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (islower(op)) {
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                op = (char) toupper(op);
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                relative = true;
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            data++;
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            data = skip_sep(data);
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        switch (op) {
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'M':
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_points(data, points, 1, relative, &c);
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.moveTo(points[0]);
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                op = 'L';
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                c = points[0];
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'L':
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_points(data, points, 1, relative, &c);
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.lineTo(points[0]);
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                c = points[0];
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'H': {
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkScalar x;
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_scalar(data, &x, relative, c.fX);
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.lineTo(x, c.fY);
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                c.fX = x;
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'V': {
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkScalar y;
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_scalar(data, &y, relative, c.fY);
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.lineTo(c.fX, y);
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                c.fY = y;
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'C':
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_points(data, points, 3, relative, &c);
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                goto cubicCommon;
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'S':
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_points(data, &points[1], 2, relative, &c);
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                points[0] = c;
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (previousOp == 'C' || previousOp == 'S') {
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    points[0].fX -= lastc.fX - c.fX;
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    points[0].fY -= lastc.fY - c.fY;
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            cubicCommon:
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //          if (data[0] == '\0')
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    //              return;
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if QUADRATIC_APPROXIMATION
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    quadApprox(fPath, points[0], points[1], points[2]);
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else   //this way just does a boring, slow old cubic
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    fPath.cubicTo(points[0], points[1], points[2]);
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        //if we are using the quadApprox, lastc is what it would have been if we had used
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        //cubicTo
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    lastc = points[1];
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    c = points[2];
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'Q':  // Quadratic Bezier Curve
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_points(data, points, 2, relative, &c);
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                goto quadraticCommon;
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'T':
19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_points(data, &points[1], 1, relative, &c);
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                points[0] = points[1];
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (previousOp == 'Q' || previousOp == 'T') {
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    points[0].fX = c.fX * 2 - lastc.fX;
19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    points[0].fY = c.fY * 2 - lastc.fY;
20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            quadraticCommon:
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.quadTo(points[0], points[1]);
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                lastc = points[0];
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                c = points[1];
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case 'Z':
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.close();
20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if 0   // !!! still a bug?
20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) {
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    c.fX -= SkScalar.Epsilon;   // !!! enough?
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    fPath.moveTo(c);
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    fPath.lineTo(f);
21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    fPath.close();
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                }
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                c = f;
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                op = '\0';
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            case '~': {
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkPoint args[2];
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                data = find_points(data, args, 2, false, NULL);
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.moveTo(args[0].fX, args[0].fY);
22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                fPath.lineTo(args[1].fX, args[1].fY);
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                break;
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            default:
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkASSERT(0);
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                return;
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (previousOp == 0)
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            f = c;
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        previousOp = op;
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (data[0] > 0);
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
235