1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2018 GRAME, Centre National de Creation Musicale
5     ---------------------------------------------------------------------
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  ************************************************************************
20  ************************************************************************/
21 
22 // SVGDev.cpp
23 
24 #include "SVGDev.h"
25 #include "exception.hh"
26 #include "global.hh"
27 
28 #include <stdio.h>
29 #include <iostream>
30 #include <sstream>
31 
32 using namespace std;
33 
xmlcode(const char * name,char * name2)34 static char* xmlcode(const char* name, char* name2)
35 {
36     int i, j;
37 
38     // SUBSTITUTION DES CARACTeRES INTERDITS EN XML
39 
40     for (i = 0, j = 0; (name[i] != 0) && (j < 250); i++) {
41         switch (name[i]) {
42             case '<':
43                 name2[j++] = '&';
44                 name2[j++] = 'l';
45                 name2[j++] = 't';
46                 name2[j++] = ';';
47                 break;
48             case '>':
49                 name2[j++] = '&';
50                 name2[j++] = 'g';
51                 name2[j++] = 't';
52                 name2[j++] = ';';
53                 break;
54             case '\'':
55                 name2[j++] = '&';
56                 name2[j++] = 'a';
57                 name2[j++] = 'p';
58                 name2[j++] = 'o';
59                 name2[j++] = 's';
60                 name2[j++] = ';';
61                 break;
62             case '"':
63                 name2[j++] = '&';
64                 name2[j++] = 'q';
65                 name2[j++] = 'u';
66                 name2[j++] = 'o';
67                 name2[j++] = 't';
68                 name2[j++] = ';';
69                 break;
70             case '&':
71                 name2[j++] = '&';
72                 name2[j++] = 'a';
73                 name2[j++] = 'm';
74                 name2[j++] = 'p';
75                 name2[j++] = ';';
76                 break;
77             default:
78                 name2[j++] = name[i];
79         }
80     }
81     name2[j] = 0;
82 
83     return name2;
84 }
85 
SVGDev(const char * ficName,double largeur,double hauteur)86 SVGDev::SVGDev(const char* ficName, double largeur, double hauteur)
87 {
88     double gScale = 0.5;
89     if ((fic_repr = fopen(ficName, "w+")) == nullptr) {
90         stringstream error;
91         error << "ERROR : impossible to create or open " << ficName << endl;
92         throw faustexception(error.str());
93     }
94 
95     // representation file:
96     fprintf(fic_repr, "<?xml version=\"1.0\"?>\n");
97     // + DTD ...
98     // viewBox:
99     if (gGlobal->gScaledSVG) {
100         fprintf(fic_repr,
101                 "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 "
102                 "%f %f\" width=\"100%%\" height=\"100%%\" version=\"1.1\">\n",
103                 largeur, hauteur);
104     } else {
105         fprintf(fic_repr,
106                 "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 "
107                 "%f %f\" width=\"%fmm\" height=\"%fmm\" version=\"1.1\">\n",
108                 largeur, hauteur, largeur * gScale, hauteur * gScale);
109     }
110 
111     if (gGlobal->gShadowBlur) {
112         fprintf(fic_repr,
113                 "<defs>\n"
114                 "   <filter id=\"filter\" filterRes=\"18\" x=\"0\" y=\"0\">\n"
115                 "     <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"1.55\" result=\"blur\"/>\n"
116                 "     <feOffset in=\"blur\" dx=\"3\" dy=\"3\"/>\n"
117                 "   </filter>\n"
118                 "</defs>\n");
119     }
120 }
121 
~SVGDev()122 SVGDev::~SVGDev()
123 {
124     fprintf(fic_repr, "</svg>\n");
125     fclose(fic_repr);
126 }
127 
rect(double x,double y,double l,double h,const char * color,const char * link)128 void SVGDev::rect(double x, double y, double l, double h, const char* color, const char* link)
129 {
130     char buf[512];
131     if (link != 0 && link[0] != 0) {
132         // open the optional link tag
133         fprintf(fic_repr, "<a xlink:href=\"%s\">\n", xmlcode(link, buf));
134     }
135     // draw the shadow
136     if (gGlobal->gShadowBlur) {
137         fprintf(fic_repr,
138                 "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" rx=\"0.1\" ry=\"0.1\" "
139                 "style=\"stroke:none;fill:#aaaaaa;;filter:url(#filter);\"/>\n",
140                 x + 1, y + 1, l, h);
141     } else {
142         fprintf(fic_repr,
143                 "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" rx=\"0\" ry=\"0\" "
144                 "style=\"stroke:none;fill:#cccccc;\"/>\n",
145                 x + 1, y + 1, l, h);
146     }
147 
148     // draw the rectangle
149     fprintf(fic_repr,
150             "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" rx=\"0\" ry=\"0\" style=\"stroke:none;fill:%s;\"/>\n",
151             x, y, l, h, color);
152     if (link != 0 && link[0] != 0) {
153         // close the optional link tag
154         fprintf(fic_repr, "</a>\n");
155     }
156 }
157 
158 //<polygon fill="lightsteelblue" stroke="midnightblue" stroke-width="5"
159 //    points="350,180 380,180 380,160 410,160 410,180 440,180 440,140 470,140 470,180
160 //    500,180 500,120 530,120 530,180" />
161 
triangle(double x,double y,double l,double h,const char * color,const char * link,bool leftright)162 void SVGDev::triangle(double x, double y, double l, double h, const char* color, const char* link, bool leftright)
163 {
164     char buf[512];
165     if (link != 0 && link[0] != 0) {
166         // open the optional link tag
167         fprintf(fic_repr, "<a xlink:href=\"%s\">\n", xmlcode(link, buf));
168     }
169     // draw triangle+circle
170     float r = 1.5;  // circle radius
171     float x0, x1, x2;
172     if (leftright) {
173         x0 = (float)x;
174         x1 = (float)(x + l - 2 * r);
175         x2 = (float)(x + l - r);
176     } else {
177         x0 = (float)(x + l);
178         x1 = (float)(x + 2 * r);
179         x2 = (float)(x + r);
180     }
181     fprintf(fic_repr, "<polygon fill=\"%s\" stroke=\"black\" stroke-width=\".25\" points=\"%f,%f %f,%f %f,%f\"/>\n",
182             color, x0, y, x1, y + h / 2.0, x0, y + h);
183     fprintf(fic_repr, "<circle  fill=\"%s\" stroke=\"black\" stroke-width=\".25\" cx=\"%f\" cy=\"%f\" r=\"%f\"/>\n",
184             color, x2, y + h / 2.0, r);
185 }
186 
rond(double x,double y,double rayon)187 void SVGDev::rond(double x, double y, double rayon)
188 {
189     fprintf(fic_repr, "<circle cx=\"%f\" cy=\"%f\" r=\"%f\"/>\n", x, y, rayon);
190 }
191 
fleche(double x,double y,double rotation,int sens)192 void SVGDev::fleche(double x, double y, double rotation, int sens)
193 {
194     double dx = 3;
195     double dy = 1;
196 
197     if (sens == 1) {
198         fprintf(fic_repr,
199                 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"  transform=\"rotate(%f,%f,%f)\" style=\"stroke: black; "
200                 "stroke-width:0.25;\"/>\n",
201                 x - dx, y - dy, x, y, rotation, x, y);
202         fprintf(fic_repr,
203                 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"  transform=\"rotate(%f,%f,%f)\" style=\"stroke: black; "
204                 "stroke-width:0.25;\"/>\n",
205                 x - dx, y + dy, x, y, rotation, x, y);
206     } else  // for recursion
207     {
208         fprintf(fic_repr,
209                 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"  transform=\"rotate(%f,%f,%f)\" style=\"stroke: black; "
210                 "stroke-width:0.25;\"/>\n",
211                 x + dx, y - dy, x, y, rotation, x, y);
212         fprintf(fic_repr,
213                 "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"  transform=\"rotate(%f,%f,%f)\" style=\"stroke: black; "
214                 "stroke-width:0.25;\"/>\n",
215                 x + dx, y + dy, x, y, rotation, x, y);
216     }
217 }
218 
carre(double x,double y,double cote)219 void SVGDev::carre(double x, double y, double cote)
220 {
221     fprintf(
222         fic_repr,
223         "<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" style=\"stroke: black;stroke-width:0.5;fill:none;\"/>\n",
224         x - 0.5 * cote, y - cote, cote, cote);
225 }
226 
trait(double x1,double y1,double x2,double y2)227 void SVGDev::trait(double x1, double y1, double x2, double y2)
228 {
229     fprintf(fic_repr,
230             "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"  style=\"stroke:black; stroke-linecap:round; "
231             "stroke-width:0.25;\"/>\n",
232             x1, y1, x2, y2);
233 }
234 
dasharray(double x1,double y1,double x2,double y2)235 void SVGDev::dasharray(double x1, double y1, double x2, double y2)
236 {
237     fprintf(fic_repr,
238             "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"  style=\"stroke: black; stroke-linecap:round; "
239             "stroke-width:0.25; stroke-dasharray:3,3;\"/>\n",
240             x1, y1, x2, y2);
241 }
242 
text(double x,double y,const char * name,const char * link)243 void SVGDev::text(double x, double y, const char* name, const char* link)
244 {
245     char buf[512];
246     if (link != 0 && link[0] != 0) {
247         // open the optional link tag
248         fprintf(fic_repr, "<a xlink:href=\"%s\">\n", xmlcode(link, buf));
249     }
250     char name2[256];
251     fprintf(fic_repr,
252             "<text x=\"%f\" y=\"%f\" font-family=\"Arial\" font-size=\"7\" text-anchor=\"middle\" "
253             "fill=\"#FFFFFF\">%s</text>\n",
254             x, y + 2, xmlcode(name, name2));
255     if (link != 0 && link[0] != 0) {
256         // close the optional link tag
257         fprintf(fic_repr, "</a>\n");
258     }
259 }
260 
label(double x,double y,const char * name)261 void SVGDev::label(double x, double y, const char* name)
262 {
263     char name2[256];
264     fprintf(fic_repr, "<text x=\"%f\" y=\"%f\" font-family=\"Arial\" font-size=\"7\">%s</text>\n", x, y + 2,
265             xmlcode(name, name2));
266 }
267 
markSens(double x,double y,int sens)268 void SVGDev::markSens(double x, double y, int sens)
269 {
270     int offset = (sens == 1) ? 2 : -2;
271     fprintf(fic_repr, "<circle cx=\"%f\" cy=\"%f\" r=\"1\"/>\n", x + offset, y + offset);
272 }
273 
Error(const char * message,const char * reason,int nb_error,double x,double y,double largeur)274 void SVGDev::Error(const char* message, const char* reason, int nb_error, double x, double y, double largeur)
275 {
276     fprintf(fic_repr,
277             "<text x=\"%f\" y=\"%f\"  textLength=\"%f\" lengthAdjust=\"spacingAndGlyphs\" style=\"stroke: red; "
278             "stroke-width:0.3; fill:red; text-anchor:middle;\">%d : %s</text>\n",
279             x, y - 7, largeur, nb_error, message);
280     fprintf(fic_repr,
281             "<text x=\"%f\" y=\"%f\"  textLength=\"%f\" lengthAdjust=\"spacingAndGlyphs\" style=\"stroke: red; "
282             "stroke-width:0.3; fill:none; text-anchor:middle;\">%s</text>\n",
283             x, y + 7, largeur, reason);
284 }
285