Home | History | Annotate | Download | only in Intersection
      1 #include <ctype.h>
      2 #include "SkPath.h"
      3 #include "SkParse.h"
      4 #include "SkPoint.h"
      5 #include "SkUtils.h"
      6 #define QUADRATIC_APPROXIMATION 0
      7 
      8 const char logoStr[] =
      9     "<path fill=\"#0081C6\""
     10     "d=\"M440.51,289.479c1.623,1.342,5.01,4.164,5.01,9.531c0,5.223-2.965,7.697-5.93,10.024"
     11     "c-0.918,0.916-1.977,1.907-1.977,3.462c0,1.551,1.059,2.397,1.834,3.035l2.545,1.973c3.105,2.613,5.928,5.016,5.928,9.889"
     12     "c0,6.635-6.426,13.341-18.566,13.341c-10.238,0-15.178-4.87-15.178-10.097c0-2.543,1.268-6.139,5.438-8.613"
     13     "c4.373-2.682,10.307-3.033,13.482-3.249c-0.99-1.271-2.119-2.61-2.119-4.798c0-1.199,0.355-1.907,0.707-2.754"
     14     "c-0.779,0.07-1.553,0.141-2.26,0.141c-7.482,0-11.719-5.579-11.719-11.082c0-3.247,1.484-6.851,4.518-9.461"
     15     "c4.025-3.318,8.824-3.883,12.639-3.883h14.541l-4.518,2.541H440.51z"
     16     "M435.494,320.826c-0.562-0.072-0.916-0.072-1.619-0.072"
     17     "c-0.637,0-4.451,0.143-7.416,1.132c-1.553,0.564-6.07,2.257-6.07,7.271c0,5.013,4.873,8.615,12.426,8.615"
     18     "c6.775,0,10.379-3.253,10.379-7.624C443.193,326.54,440.863,324.64,435.494,320.826z"
     19     "M437.543,307.412"
     20     "c1.623-1.627,1.764-3.883,1.764-5.154c0-5.083-3.035-12.99-8.893-12.99c-1.838,0-3.812,0.918-4.945,2.331"
     21     "c-1.199,1.483-1.551,3.387-1.551,5.225c0,4.729,2.754,12.565,8.826,12.565C434.508,309.389,436.41,308.543,437.543,307.412z\"/>"
     22     "<path fill=\"#FFD200\""
     23     "d=\"M396.064,319.696c-11.206,0-17.198-8.739-17.198-16.636c0-9.233,7.542-17.126,18.258-17.126"
     24     "c10.357,0,16.844,8.104,16.844,16.635C413.969,310.884,407.557,319.696,396.064,319.696z"
     25     "M404.873,313.987"
     26     "c1.695-2.257,2.119-5.074,2.119-7.826c0-6.202-2.961-18.042-11.701-18.042c-2.326,0-4.652,0.918-6.342,2.399"
     27     "c-2.749,2.465-3.245,5.566-3.245,8.599c0,6.977,3.454,18.463,11.984,18.463C400.436,317.58,403.256,316.242,404.873,313.987z\"/>"
     28     "<path fill=\"#ED174F\""
     29     "d=\"M357.861,319.696c-11.207,0-17.199-8.739-17.199-16.636c0-9.233,7.544-17.126,18.258-17.126"
     30     "c10.359,0,16.845,8.104,16.845,16.635C375.764,310.884,369.351,319.696,357.861,319.696z"
     31     "M366.671,313.987"
     32     "c1.693-2.257,2.116-5.074,2.116-7.826c0-6.202-2.961-18.042-11.701-18.042c-2.325,0-4.652,0.918-6.344,2.399"
     33     "c-2.749,2.465-3.241,5.566-3.241,8.599c0,6.977,3.452,18.463,11.983,18.463C362.234,317.58,365.053,316.242,366.671,313.987z\"/>"
     34     "<path fill=\"#0081C6\""
     35     "d=\"M335.278,318.591l-10.135,2.339c-4.111,0.638-7.795,1.204-11.69,1.204"
     36     "c-19.56,0-26.998-14.386-26.998-25.654c0-13.746,10.558-26.498,28.629-26.498c3.827,0,7.51,0.564,10.839,1.486"
     37     "c5.316,1.488,7.796,3.331,9.355,4.394l-5.883,5.599l-2.479,0.565l1.771-2.837c-2.408-2.336-6.805-6.658-15.164-6.658"
     38     "c-11.196,0-19.63,8.507-19.63,20.906c0,13.319,9.638,25.861,25.084,25.861c4.539,0,6.874-0.918,9-1.771v-11.407l-10.698,0.566"
     39     "l5.667-3.047h15.023l-1.841,1.77c-0.5,0.424-0.567,0.57-0.71,1.133c-0.073,0.64-0.141,2.695-0.141,3.403V318.591z\"/>"
     40     "<path fill=\"#49A942\""
     41     "d=\"M462.908,316.552c-2.342-0.214-2.832-0.638-2.832-3.401v-0.782v-39.327c0.014-0.153,0.025-0.31,0.041-0.457"
     42     "c0.283-2.479,0.992-2.903,3.189-4.182h-10.135l-5.316,2.552h5.418v0.032l-0.004-0.024v41.406v2.341"
     43     "c0,1.416-0.281,1.629-1.912,3.753H463.9l2.623-1.557C465.318,316.763,464.113,316.692,462.908,316.552z\"/>"
     44     "<path fill=\"#ED174F\""
     45     "d=\"M491.742,317.203c-0.771,0.422-1.547,0.916-2.318,1.268c-2.326,1.055-4.719,1.336-6.83,1.336"
     46     "c-2.25,0-5.77-0.143-9.361-2.744c-4.992-3.521-7.176-9.572-7.176-14.851c0-10.906,8.869-16.255,16.115-16.255"
     47     "c2.533,0,5.141,0.633,7.252,1.972c3.516,2.318,4.43,5.344,4.922,6.963l-16.535,6.688l-5.422,0.422"
     48     "c1.758,8.938,7.812,14.145,14.498,14.145c3.59,0,6.193-1.266,8.586-2.461L491.742,317.203z"
     49     "M485.129,296.229"
     50     "c1.336-0.493,2.039-0.914,2.039-1.899c0-2.812-3.166-6.053-6.967-6.053c-2.818,0-8.094,2.183-8.094,9.783"
     51     "c0,1.197,0.141,2.464,0.213,3.73L485.129,296.229z\"/>"
     52     "<path fill=\"#77787B\""
     53     "d=\"M498.535,286.439v4.643h-0.564v-4.643h-1.537v-0.482h3.637v0.482H498.535z\"/>"
     54     "<path fill=\"#77787B\""
     55     "d=\"M504.863,291.082v-4.687h-0.023l-1.432,4.687h-0.439l-1.443-4.687h-0.02v4.687h-0.512v-5.125h0.877"
     56     "l1.307,4.143h0.018l1.285-4.143h0.891v5.125H504.863z\"/>"
     57 ;
     58 
     59 size_t logoStrLen = sizeof(logoStr);
     60 
     61 #if QUADRATIC_APPROXIMATION
     62 ////////////////////////////////////////////////////////////////////////////////////
     63 //functions to approximate a cubic using two quadratics
     64 
     65 //      midPt sets the first argument to be the midpoint of the other two
     66 //      it is used by quadApprox
     67 static inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b)
     68 {
     69     dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY));
     70 }
     71 //      quadApprox - makes an approximation, which we hope is faster
     72 static void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
     73 {
     74     //divide the cubic up into two cubics, then convert them into quadratics
     75     //define our points
     76     SkPoint c,j,k,l,m,n,o,p,q, mid;
     77     fPath.getLastPt(&c);
     78     midPt(j, p0, c);
     79     midPt(k, p0, p1);
     80     midPt(l, p1, p2);
     81     midPt(o, j, k);
     82     midPt(p, k, l);
     83     midPt(q, o, p);
     84     //compute the first half
     85     m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY));
     86     n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY));
     87     midPt(mid,m,n);
     88     fPath.quadTo(mid,q);
     89     c = q;
     90     //compute the second half
     91     m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY));
     92     n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY));
     93     midPt(mid,m,n);
     94     fPath.quadTo(mid,p2);
     95 }
     96 #endif
     97 
     98 
     99 static inline bool is_between(int c, int min, int max)
    100 {
    101     return (unsigned)(c - min) <= (unsigned)(max - min);
    102 }
    103 
    104 static inline bool is_ws(int c)
    105 {
    106     return is_between(c, 1, 32);
    107 }
    108 
    109 static inline bool is_digit(int c)
    110 {
    111     return is_between(c, '0', '9');
    112 }
    113 
    114 static inline bool is_sep(int c)
    115 {
    116     return is_ws(c) || c == ',';
    117 }
    118 
    119 static const char* skip_ws(const char str[])
    120 {
    121     SkASSERT(str);
    122     while (is_ws(*str))
    123         str++;
    124     return str;
    125 }
    126 
    127 static const char* skip_sep(const char str[])
    128 {
    129     SkASSERT(str);
    130     while (is_sep(*str))
    131         str++;
    132     return str;
    133 }
    134 
    135 static const char* find_points(const char str[], SkPoint value[], int count,
    136      bool isRelative, SkPoint* relative)
    137 {
    138     str = SkParse::FindScalars(str, &value[0].fX, count * 2);
    139     if (isRelative) {
    140         for (int index = 0; index < count; index++) {
    141             value[index].fX += relative->fX;
    142             value[index].fY += relative->fY;
    143         }
    144     }
    145     return str;
    146 }
    147 
    148 static const char* find_scalar(const char str[], SkScalar* value,
    149     bool isRelative, SkScalar relative)
    150 {
    151     str = SkParse::FindScalar(str, value);
    152     if (isRelative)
    153         *value += relative;
    154     return str;
    155 }
    156 
    157 static void showPathContour(SkPath::Iter& iter) {
    158     uint8_t verb;
    159     SkPoint pts[4];
    160     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
    161         switch (verb) {
    162             case SkPath::kMove_Verb:
    163                 SkDebugf("path.moveTo(%1.9gf,%1.9gf);\n", pts[0].fX, pts[0].fY);
    164                 continue;
    165             case SkPath::kLine_Verb:
    166                 SkDebugf("path.lineTo(%1.9gf,%1.9gf);\n", pts[1].fX, pts[1].fY);
    167                 break;
    168             case SkPath::kQuad_Verb:
    169                 SkDebugf("path.quadTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf);\n",
    170                     pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
    171                 break;
    172             case SkPath::kCubic_Verb:
    173                 SkDebugf("path.cubicTo(%1.9gf,%1.9gf, %1.9gf,%1.9gf, %1.9gf,%1.9gf);\n",
    174                     pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
    175                 break;
    176             case SkPath::kClose_Verb:
    177                 SkDebugf("path.close();\n");
    178                 break;
    179             default:
    180                 SkDEBUGFAIL("bad verb");
    181                 return;
    182         }
    183     }
    184 }
    185 
    186 static void showPath(const SkPath& path) {
    187     SkPath::Iter iter(path, true);
    188     int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
    189     if (rectCount > 0) {
    190         SkTDArray<SkRect> rects;
    191         SkTDArray<SkPath::Direction> directions;
    192         rects.setCount(rectCount);
    193         directions.setCount(rectCount);
    194         path.rectContours(rects.begin(), directions.begin());
    195         for (int contour = 0; contour < rectCount; ++contour) {
    196             const SkRect& rect = rects[contour];
    197             SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
    198                     rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
    199                     ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
    200         }
    201         return;
    202     }
    203     iter.setPath(path, true);
    204     showPathContour(iter);
    205 }
    206 
    207 static const char* parsePath(const char* data) {
    208     SkPath fPath;
    209     SkPoint f = {0, 0};
    210     SkPoint c = {0, 0};
    211     SkPoint lastc = {0, 0};
    212     SkPoint points[3];
    213     char op = '\0';
    214     char previousOp = '\0';
    215     bool relative = false;
    216     do {
    217         data = skip_ws(data);
    218         if (data[0] == '\0')
    219             break;
    220         char ch = data[0];
    221         if (is_digit(ch) || ch == '-' || ch == '+') {
    222             if (op == '\0') {
    223                 SkASSERT(0);
    224                 return 0;
    225             }
    226         }
    227         else {
    228             op = ch;
    229             relative = false;
    230             if (islower(op)) {
    231                 op = (char) toupper(op);
    232                 relative = true;
    233             }
    234             data++;
    235             data = skip_sep(data);
    236         }
    237         switch (op) {
    238             case 'M':
    239                 data = find_points(data, points, 1, relative, &c);
    240                 fPath.moveTo(points[0]);
    241                 op = 'L';
    242                 c = points[0];
    243                 break;
    244             case 'L':
    245                 data = find_points(data, points, 1, relative, &c);
    246                 fPath.lineTo(points[0]);
    247                 c = points[0];
    248                 break;
    249             case 'H': {
    250                 SkScalar x;
    251                 data = find_scalar(data, &x, relative, c.fX);
    252                 fPath.lineTo(x, c.fY);
    253                 c.fX = x;
    254             }
    255                 break;
    256             case 'V': {
    257                 SkScalar y;
    258                 data = find_scalar(data, &y, relative, c.fY);
    259                 fPath.lineTo(c.fX, y);
    260                 c.fY = y;
    261             }
    262                 break;
    263             case 'C':
    264                 data = find_points(data, points, 3, relative, &c);
    265                 goto cubicCommon;
    266             case 'S':
    267                 data = find_points(data, &points[1], 2, relative, &c);
    268                 points[0] = c;
    269                 if (previousOp == 'C' || previousOp == 'S') {
    270                     points[0].fX -= lastc.fX - c.fX;
    271                     points[0].fY -= lastc.fY - c.fY;
    272                 }
    273             cubicCommon:
    274     //          if (data[0] == '\0')
    275     //              return;
    276 #if QUADRATIC_APPROXIMATION
    277                     quadApprox(fPath, points[0], points[1], points[2]);
    278 #else   //this way just does a boring, slow old cubic
    279                     fPath.cubicTo(points[0], points[1], points[2]);
    280 #endif
    281         //if we are using the quadApprox, lastc is what it would have been if we had used
    282         //cubicTo
    283                     lastc = points[1];
    284                     c = points[2];
    285                 break;
    286             case 'Q':  // Quadratic Bezier Curve
    287                 data = find_points(data, points, 2, relative, &c);
    288                 goto quadraticCommon;
    289             case 'T':
    290                 data = find_points(data, &points[1], 1, relative, &c);
    291                 points[0] = points[1];
    292                 if (previousOp == 'Q' || previousOp == 'T') {
    293                     points[0].fX = c.fX * 2 - lastc.fX;
    294                     points[0].fY = c.fY * 2 - lastc.fY;
    295                 }
    296             quadraticCommon:
    297                 fPath.quadTo(points[0], points[1]);
    298                 lastc = points[0];
    299                 c = points[1];
    300                 break;
    301             case 'Z':
    302                 fPath.close();
    303 #if 0   // !!! still a bug?
    304                 if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) {
    305                     c.fX -= SkScalar.Epsilon;   // !!! enough?
    306                     fPath.moveTo(c);
    307                     fPath.lineTo(f);
    308                     fPath.close();
    309                 }
    310 #endif
    311                 c = f;
    312                 op = '\0';
    313                 break;
    314             case '~': {
    315                 SkPoint args[2];
    316                 data = find_points(data, args, 2, false, NULL);
    317                 fPath.moveTo(args[0].fX, args[0].fY);
    318                 fPath.lineTo(args[1].fX, args[1].fY);
    319             }
    320                 break;
    321             default:
    322                 SkASSERT(0);
    323                 return 0;
    324         }
    325         if (previousOp == 0)
    326             f = c;
    327         previousOp = op;
    328     } while (data[0] != '"');
    329     showPath(fPath);
    330     return data;
    331 }
    332 
    333 const char pathPrefix[] = "<path fill=\"";
    334 
    335 void parseSVG();
    336 void parseSVG() {
    337     const char* data = logoStr;
    338     const char* dataEnd = logoStr + logoStrLen - 1;
    339     while (data < dataEnd) {
    340         SkASSERT(strncmp(data, pathPrefix, sizeof(pathPrefix) - 1) == 0);
    341         data += sizeof(pathPrefix) - 1;
    342         SkDebugf("paint.setColor(0xFF%c%c%c%c%c%c);\n", data[1], data[2], data[3], data[4],
    343             data[5], data[6]);
    344         data += 8;
    345         SkASSERT(strncmp(data, "d=\"", 3) == 0);
    346         data += 3;
    347         SkDebugf("path.reset();\n");
    348         data = parsePath(data);
    349         SkDebugf("canvas->drawPath(path, paint);\n");
    350         SkASSERT(strncmp(data, "\"/>", 3) == 0);
    351         data += 3;
    352     }
    353 }
    354