summaryrefslogtreecommitdiffstats
path: root/src/svg/svg-affine-parser.rl
blob: 616ff449f1982f17099983cba56ffe0eb94f8886 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * SVG data parser
 *
 * Authors:
 *   Marc Jeanmougin <marc.jeanmougin@telecom-paris.fr>
 *
 * Copyright (C) 2019 Marc Jeanmougin (.rl parser, CSS-transform spec)
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 *
 * THE CPP FILE IS GENERATED FROM THE RL FILE, DO NOT EDIT THE CPP
 *
 * To generate it, run
 *   ragel svg-affine-parser.rl -o svg-affine-parser.cpp
 *   sed -Ei 's/\(1\)/(true)/' svg-affine-parser.cpp
 */

#include <string>
#include <glib.h>
#include <2geom/transforms.h>
#include "svg.h"
#include "preferences.h"

%%{
    machine svg_transform;
    write data noerror;
}%%

// https://www.w3.org/TR/css-transforms-1/#svg-syntax
bool sp_svg_transform_read(gchar const *str, Geom::Affine *transform)
{
    if (str == nullptr)
        return false;

    std::vector<double> params;
    Geom::Affine final_transform (Geom::identity());
    *transform = final_transform;
    Geom::Affine tmp_transform (Geom::identity());
    int cs;
    const char *p = str;
    const char *pe = p + strlen(p) + 1;
    const char *eof = pe;
    char const *start_num = 0;
    char const *ts = p;
    char const *te = pe;
    int act = 0;
    if (pe == p+1) return true; // ""

%%{
    write init;

    action number {
      std::string buf(start_num, p); 
      params.push_back(g_ascii_strtod(buf.c_str(), NULL));
    }

    action translate { tmp_transform = Geom::Translate(params[0], params.size() == 1 ? 0 : params[1]); }
    action scale { tmp_transform = Geom::Scale(params[0], params.size() == 1 ? params[0] : params[1]); }
    action rotate {
        if (params.size() == 1) 
            tmp_transform = Geom::Rotate(Geom::rad_from_deg(params[0])); 
        else {
            tmp_transform = Geom::Translate(-params[1], -params[2]) * 
                            Geom::Rotate(Geom::rad_from_deg(params[0])) * 
                            Geom::Translate(params[1], params[2]); 
        } 
    }
    action skewX { tmp_transform = Geom::Affine(1, 0, tan(params[0] * M_PI / 180.0), 1, 0, 0); }
    action skewY { tmp_transform = Geom::Affine(1, tan(params[0] * M_PI / 180.0), 0, 1, 0, 0); }
    action matrix { tmp_transform = Geom::Affine(params[0], params[1], params[2], params[3], params[4], params[5]);}
    action transform {params.clear(); final_transform = tmp_transform * final_transform ;}
    action transformlist { *transform = final_transform; /*printf("%p %p %p %p
%d\n",p, pe, ts, te, cs);*/ return (te+1 == pe);}

    comma = ',';
    wsp = ( 10 | 13 | 9 | ' ');
    sign = ('+' | '-');
    digit_sequence = digit+;
    exponent = ('e' | 'E') sign? digit_sequence;
    fractional_constant = digit_sequence? '.' digit_sequence
            | digit_sequence '.';
    floating_point_constant = fractional_constant exponent?
            | digit_sequence exponent;
    integer_constant = digit_sequence;
    number = ( sign? integer_constant | sign? floating_point_constant )
           > {start_num = p;}
           %number;

    commawsp = (wsp+ comma? wsp*) | (comma wsp*);
    translate = "translate" wsp* "(" wsp* number <: ( commawsp? number )? wsp* ")"
      %translate;
    scale = "scale" wsp* "(" wsp* number <: ( commawsp? number )? wsp* ")"
      %scale;
    rotate = "rotate" wsp* "(" wsp* number <: ( commawsp? number <: commawsp? number )? wsp* ")"
      %rotate;
    skewX = "skewX" wsp* "(" wsp* number wsp* ")"
      %skewX;
    skewY = "skewY" wsp* "(" wsp* number wsp* ")"
      %skewY;
    matrix = "matrix" wsp* "(" wsp*
      number <: commawsp?
      number <: commawsp?
      number <: commawsp?
      number <: commawsp?
      number <: commawsp?
      number wsp* ")"
      %matrix;
    transform = (matrix | translate | scale | rotate | skewX | skewY)
      %transform;
    transforms = transform ( commawsp? transform )**;
    transformlist = wsp* transforms? wsp*;
    main := |* 
      transformlist => transformlist;
    *|;
    write exec;
}%%
    g_warning("could not parse transform attribute");

    return false;
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=ragel:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :