Code

df9c4605116328ce24ff7a02a958cdca9325c433
[inkscape.git] / src / svg / svg-path-nr-test.h
1 #include <cxxtest/TestSuite.h>
2 #include "libnr/n-art-bpath.h"
3 #include "svg/svg.h"
4 #include "2geom/coord.h"
5 #include "prefs-utils.h"
6 #include "streq.h"
7 #include <string>
8 #include <vector>
9 #include <glib/gmem.h>
11 class SvgPathNRTest : public CxxTest::TestSuite
12 {
13 private:
14     std::vector<std::string> rectanglesAbsoluteClosed;
15     std::vector<std::string> rectanglesRelativeClosed;
16     std::vector<std::string> rectanglesAbsoluteOpen;
17     std::vector<std::string> rectanglesRelativeOpen;
18     NArtBpath rectangleBpath[5+1];
19 public:
20     SvgPathNRTest() {
21         // Lots of ways to define the same rectangle
22         rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 Z");
23         rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 z");
24         rectanglesAbsoluteClosed.push_back("M 1,2 4,2 4,8 1,8 z");
25         rectanglesAbsoluteClosed.push_back("M 1,2 H 4 V 8 H 1 z");
26         rectanglesRelativeClosed.push_back("m 1,2 l 3,0 l 0,6 l -3,0 z");
27         rectanglesRelativeClosed.push_back("m 1,2 3,0 0,6 -3,0 z");
28         rectanglesRelativeClosed.push_back("m 1,2 h 3 v 6 h -3 z");
29         rectanglesAbsoluteOpen.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2");
30         rectanglesAbsoluteOpen.push_back("M 1,2 4,2 4,8 1,8 1,2");
31         rectanglesAbsoluteOpen.push_back("M 1,2 H 4 V 8 H 1 V 2");
32         rectanglesRelativeOpen.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6");
33         rectanglesRelativeOpen.push_back("m 1,2 3,0 0,6 -3,0 0,-6");
34         rectanglesRelativeOpen.push_back("m 1,2 h 3 v 6 h -3 v -6");
35         rectangleBpath[0].code = NR_MOVETO;
36         rectangleBpath[0].x3 = 1;
37         rectangleBpath[0].y3 = 2;
38         rectangleBpath[1].code = NR_LINETO;
39         rectangleBpath[1].x3 = 4;
40         rectangleBpath[1].y3 = 2;
41         rectangleBpath[2].code = NR_LINETO;
42         rectangleBpath[2].x3 = 4;
43         rectangleBpath[2].y3 = 8;
44         rectangleBpath[3].code = NR_LINETO;
45         rectangleBpath[3].x3 = 1;
46         rectangleBpath[3].y3 = 8;
47         rectangleBpath[4].code = NR_LINETO;
48         rectangleBpath[4].x3 = 1;
49         rectangleBpath[4].y3 = 2;
50         rectangleBpath[5].code = NR_END;
51         // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs
52     }
54 // createSuite and destroySuite get us per-suite setup and teardown
55 // without us having to worry about static initialization order, etc.
56     static SvgPathNRTest *createSuite() { return new SvgPathNRTest(); }
57     static void destroySuite( SvgPathNRTest *suite ) { delete suite; }
59     void testReadRectanglesAbsoluteClosed()
60     {
61         rectangleBpath[0].code = NR_MOVETO;
62         for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {
63             NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteClosed[i].c_str());
64             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
65             g_free(bpath);
66         }
67     }
69     void testReadRectanglesRelativeClosed()
70     {
71         rectangleBpath[0].code = NR_MOVETO;
72         for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {
73             NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeClosed[i].c_str());
74             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
75             g_free(bpath);
76         }
77     }
79     void testReadRectanglesAbsoluteOpen()
80     {
81         rectangleBpath[0].code = NR_MOVETO_OPEN;
82         for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {
83             NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteOpen[i].c_str());
84             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
85             g_free(bpath);
86         }
87     }
89     void testReadRectanglesRelativeOpen()
90     {
91         rectangleBpath[0].code = NR_MOVETO_OPEN;
92         for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {
93             NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeOpen[i].c_str());
94             TS_ASSERT(bpathEqual(bpath,rectangleBpath));
95             g_free(bpath);
96         }
97     }
99     void testReadConcatenatedPaths()
100     {
101         NArtBpath bpath_good[4*5+1];
102         for(size_t i=0; i<4; i++) {
103             memcpy(bpath_good+i*5,rectangleBpath,sizeof(rectangleBpath[0])*5);
104         }
105         bpath_good[0*5].code = NR_MOVETO;
106         bpath_good[1*5].code = NR_MOVETO_OPEN;
107         bpath_good[2*5].code = NR_MOVETO;
108         bpath_good[3*5].code = NR_MOVETO_OPEN;
109         bpath_good[4*5].code = NR_END;
110         for(size_t i=0; i<5; i++) {
111             bpath_good[1*5+i].x3 += bpath_good[0*5+4].x3;
112             bpath_good[1*5+i].y3 += bpath_good[0*5+4].y3;
113         }
114         for(size_t i=0; i<5; i++) {
115             bpath_good[2*5+i].x3 += bpath_good[1*5+4].x3;
116             bpath_good[2*5+i].y3 += bpath_good[1*5+4].y3;
117         }
118         std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];
119         NArtBpath * bpath = sp_svg_read_path(path_str.c_str());
120         TS_ASSERT(bpathEqual(bpath,bpath_good));
121         g_free(bpath);
122     }
124     void testReadZeroLengthSubpaths() {
125         // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant
126         NArtBpath bpath_good[8+1];
127         bpath_good[0].code = NR_MOVETO_OPEN;
128         bpath_good[0].x3 = bpath_good[0].y3 = 0;
129         bpath_good[1].code = NR_MOVETO_OPEN;
130         bpath_good[1].x3 = bpath_good[1].y3 = 1;
131         bpath_good[2].code = NR_LINETO;
132         bpath_good[2].x3 = bpath_good[2].y3 = 2;
133         bpath_good[3].code = NR_MOVETO;
134         bpath_good[3].x3 = bpath_good[3].y3 = 3;
135         bpath_good[4].code = NR_MOVETO;
136         bpath_good[4].x3 = bpath_good[4].y3 = 4;
137         bpath_good[5].code = NR_LINETO;
138         bpath_good[5].x3 = bpath_good[5].y3 = 5;
139         bpath_good[6].code = NR_LINETO;
140         bpath_good[6].x3 = bpath_good[6].y3 = 4;
141         bpath_good[7].code = NR_MOVETO_OPEN;
142         bpath_good[7].x3 = bpath_good[7].y3 = 6;
143         bpath_good[8].code = NR_END;
144         {   // Test absolute version
145             char const * path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6";
146             NArtBpath * bpath = sp_svg_read_path(path_str);
147             TS_ASSERT(bpathEqual(bpath,bpath_good));
148             g_free(bpath);
149         }
150         {   // Test relative version
151             char const * path_str = "m 0,0 m 1,1 l 1,1 m 1,1 z m 1,1 l 1,1 z m 2,2";
152             NArtBpath * bpath = sp_svg_read_path(path_str);
153             TS_ASSERT(bpathEqual(bpath,bpath_good));
154             g_free(bpath);
155         }
156     }
158     void testReadImplicitMoveto() {
159         NArtBpath bpath_good[6+1];
160         bpath_good[0].code = NR_MOVETO;
161         bpath_good[0].x3 = bpath_good[0].y3 = 1;
162         bpath_good[1].code = NR_LINETO;
163         bpath_good[1].x3 = bpath_good[1].y3 = 2;
164         bpath_good[2].code = NR_LINETO;
165         bpath_good[2].x3 = bpath_good[2].y3 = 1;
166         bpath_good[3].code = NR_MOVETO;
167         bpath_good[3].x3 = bpath_good[3].y3 = 1;
168         bpath_good[4].code = NR_LINETO;
169         bpath_good[4].x3 = bpath_good[4].y3 = 3;
170         bpath_good[5].code = NR_LINETO;
171         bpath_good[5].x3 = bpath_good[5].y3 = 1;
172         bpath_good[6].code = NR_END;
173         {   // Test absolute version
174             char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
175             NArtBpath * bpath = sp_svg_read_path(path_str);
176             TS_ASSERT(bpathEqual(bpath,bpath_good));
177             g_free(bpath);
178         }
179         {   // Test relative version
180             char const * path_str = "M 1,1 L 2,2 z L 3,3 z";
181             NArtBpath * bpath = sp_svg_read_path(path_str);
182             TS_ASSERT(bpathEqual(bpath,bpath_good));
183             g_free(bpath);
184         }
185     }
187     void testReadFloatingPoint() {
188         NArtBpath bpath_good[5+1];
189         bpath_good[0].code = NR_MOVETO;
190         bpath_good[0].x3 = .01;
191         bpath_good[0].y3 = .02;
192         bpath_good[1].code = NR_LINETO;
193         bpath_good[1].x3 = .04;
194         bpath_good[1].y3 = .02;
195         bpath_good[2].code = NR_LINETO;
196         bpath_good[2].x3 = 1.5;
197         bpath_good[2].y3 = 1.6;
198         bpath_good[3].code = NR_LINETO;
199         bpath_good[3].x3 = .01;
200         bpath_good[3].y3 = .08;
201         bpath_good[4].code = NR_LINETO;
202         bpath_good[4].x3 = .01;
203         bpath_good[4].y3 = .02;
204         bpath_good[5].code = NR_END;
205         {   // Test decimals
206             char const * path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z";
207             NArtBpath * bpath = sp_svg_read_path(path_str);
208             TS_ASSERT(bpathEqual(bpath,bpath_good));
209             g_free(bpath);
210         }
211         {   // Test exponent
212             char const * path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L0150E-2,1.6e0L1.0e-2,80e-3 z";
213             NArtBpath * bpath = sp_svg_read_path(path_str);
214             TS_ASSERT(bpathEqual(bpath,bpath_good));
215             g_free(bpath);
216         }
217     }
219     void testReadImplicitSeparation() {
220         // Coordinates need not be separated by whitespace if they can still be read unambiguously
221         NArtBpath bpath_good[5+1];
222         bpath_good[0].code = NR_MOVETO;
223         bpath_good[0].x3 = .1;
224         bpath_good[0].y3 = .2;
225         bpath_good[1].code = NR_LINETO;
226         bpath_good[1].x3 = .4;
227         bpath_good[1].y3 = .2;
228         bpath_good[2].code = NR_LINETO;
229         bpath_good[2].x3 = .4;
230         bpath_good[2].y3 = .8;
231         bpath_good[3].code = NR_LINETO;
232         bpath_good[3].x3 = .1;
233         bpath_good[3].y3 = .8;
234         bpath_good[4].code = NR_LINETO;
235         bpath_good[4].x3 = .1;
236         bpath_good[4].y3 = .2;
237         bpath_good[5].code = NR_END;
238         {   // Test absolute
239             char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";
240             NArtBpath * bpath = sp_svg_read_path(path_str);
241             TS_ASSERT(bpathEqual(bpath,bpath_good));
242             g_free(bpath);
243         }
244         {   // Test relative
245             char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";
246             NArtBpath * bpath = sp_svg_read_path(path_str);
247             TS_ASSERT(bpathEqual(bpath,bpath_good));
248             g_free(bpath);
249         }
250     }
252     void testReadErrorMisplacedCharacter() {
253         char const * path_str;
254         NArtBpath * bpath;
255         NArtBpath * bpath_good = rectangleBpath;
256         bpath_good[0].code = NR_MOVETO;
257         // Comma in the wrong place (commas may only appear between parameters)
258         path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15";
259         bpath = sp_svg_read_path(path_str);
260         TS_ASSERT(bpathEqual(bpath,bpath_good));
261         g_free(bpath);
262         // Comma in the wrong place (commas may only appear between parameters)
263         path_str = "M 1,2 4,2 4,8 1,8 z m,13,15";
264         bpath = sp_svg_read_path(path_str);
265         TS_ASSERT(bpathEqual(bpath,bpath_good));
266         g_free(bpath);
267         // Period in the wrong place (no numbers after a 'z')
268         path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15";
269         bpath = sp_svg_read_path(path_str);
270         TS_ASSERT(bpathEqual(bpath,bpath_good));
271         g_free(bpath);
272         // Sign in the wrong place (no numbers after a 'z')
273         path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15";
274         bpath = sp_svg_read_path(path_str);
275         TS_ASSERT(bpathEqual(bpath,bpath_good));
276         g_free(bpath);
277         // Digit in the wrong place (no numbers after a 'z')
278         path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15";
279         bpath = sp_svg_read_path(path_str);
280         TS_ASSERT(bpathEqual(bpath,bpath_good));
281         g_free(bpath);
282         // Digit in the wrong place (no numbers after a 'z')
283         path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15";
284         bpath = sp_svg_read_path(path_str);
285         TS_ASSERT(bpathEqual(bpath,bpath_good));
286         g_free(bpath);
287     }
289     void testReadErrorUnrecognizedCharacter() {
290         char const * path_str;
291         NArtBpath * bpath;
292         NArtBpath * bpath_good = rectangleBpath;
293         bpath_good[0].code = NR_MOVETO;
294         // Unrecognized character
295         path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";
296         bpath = sp_svg_read_path(path_str);
297         TS_ASSERT(bpathEqual(bpath,bpath_good));
298         g_free(bpath);
299         // Unrecognized character
300         path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";
301         bpath = sp_svg_read_path(path_str);
302         TS_ASSERT(bpathEqual(bpath,bpath_good));
303         g_free(bpath);
304     }
306     void testReadErrorTypo() {
307         char const * path_str;
308         NArtBpath * bpath;
309         NArtBpath * bpath_good = rectangleBpath;
310         bpath_good[0].code = NR_MOVETO;
311         // Typo
312         path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";
313         bpath = sp_svg_read_path(path_str);
314         TS_ASSERT(bpathEqual(bpath,bpath_good));
315         g_free(bpath);
317         bpath_good[0].code = NR_MOVETO_OPEN;
318         // Typo
319         path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";
320         bpath = sp_svg_read_path(path_str);
321         TS_ASSERT(bpathEqual(bpath,bpath_good));
322         g_free(bpath);
323     }
325     void testReadErrorIllformedNumbers() {
326         char const * path_str;
327         NArtBpath * bpath;
328         NArtBpath * bpath_good = rectangleBpath;
329         bpath_good[0].code = NR_MOVETO;
330         // Double exponent
331         path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";
332         bpath = sp_svg_read_path(path_str);
333         TS_ASSERT(bpathEqual(bpath,bpath_good));
334         g_free(bpath);
335         // Double sign
336         path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";
337         bpath = sp_svg_read_path(path_str);
338         TS_ASSERT(bpathEqual(bpath,bpath_good));
339         g_free(bpath);
340         // Double sign
341         path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";
342         bpath = sp_svg_read_path(path_str);
343         TS_ASSERT(bpathEqual(bpath,bpath_good));
344         g_free(bpath);
345         // No digit
346         path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";
347         bpath = sp_svg_read_path(path_str);
348         TS_ASSERT(bpathEqual(bpath,bpath_good));
349         g_free(bpath);
350         // No digit
351         path_str = "M 1,2 4,2 4,8 1,8 z m .,15";
352         bpath = sp_svg_read_path(path_str);
353         TS_ASSERT(bpathEqual(bpath,bpath_good));
354         g_free(bpath);
355         // No digit
356         path_str = "M 1,2 4,2 4,8 1,8 z m +,15";
357         bpath = sp_svg_read_path(path_str);
358         TS_ASSERT(bpathEqual(bpath,bpath_good));
359         g_free(bpath);
360         // No digit
361         path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";
362         bpath = sp_svg_read_path(path_str);
363         TS_ASSERT(bpathEqual(bpath,bpath_good));
364         g_free(bpath);
365     }
367     void testReadErrorJunk() {
368         char const * path_str;
369         NArtBpath * bpath;
370         NArtBpath * bpath_good = rectangleBpath;
371         bpath_good[0].code = NR_MOVETO;
372         // Junk
373         path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23";
374         bpath = sp_svg_read_path(path_str);
375         TS_ASSERT(bpathEqual(bpath,bpath_good));
376         g_free(bpath);
377     }
379     void testReadErrorStopReading() {
380         char const * path_str;
381         NArtBpath * bpath;
382         NArtBpath * bpath_good = rectangleBpath;
383         bpath_good[0].code = NR_MOVETO;
384         // Unrecognized parameter
385         path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
386         bpath = sp_svg_read_path(path_str);
387         TS_ASSERT(bpathEqual(bpath,bpath_good));
388         g_free(bpath);
389         // Invalid parameter
390         path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";
391         bpath = sp_svg_read_path(path_str);
392         TS_ASSERT(bpathEqual(bpath,bpath_good));
393         g_free(bpath);
394         // Illformed parameter
395         path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";
396         bpath = sp_svg_read_path(path_str);
397         TS_ASSERT(bpathEqual(bpath,bpath_good));
398         g_free(bpath);
400         bpath_good[0].code = NR_MOVETO_OPEN;
401         // "Third" parameter
402         path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";
403         bpath = sp_svg_read_path(path_str);
404         TS_ASSERT(bpathEqual(bpath,bpath_good));
405         g_free(bpath);
406     }
408     void testRoundTrip() {
409         // This is the easiest way to (also) test writing path data, as a path can be written in more than one way.
410         NArtBpath * bpath;
411         NArtBpath * new_bpath;
412         char * path_str;
413         // Rectangle (closed)
414         bpath = sp_svg_read_path(rectanglesAbsoluteClosed[0].c_str());
415         path_str = sp_svg_write_path(bpath);
416         new_bpath = sp_svg_read_path(path_str);
417         TS_ASSERT(bpathEqual(bpath,new_bpath));
418         g_free(bpath); g_free(path_str); g_free(new_bpath);
419         // Rectangle (open)
420         bpath = sp_svg_read_path(rectanglesAbsoluteOpen[0].c_str());
421         path_str = sp_svg_write_path(bpath);
422         new_bpath = sp_svg_read_path(path_str);
423         TS_ASSERT(bpathEqual(bpath,new_bpath));
424         g_free(bpath); g_free(path_str); g_free(new_bpath);
425         // Concatenated rectangles
426         bpath = sp_svg_read_path((rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0]).c_str());
427         path_str = sp_svg_write_path(bpath);
428         new_bpath = sp_svg_read_path(path_str);
429         TS_ASSERT(bpathEqual(bpath,new_bpath));
430         g_free(bpath); g_free(path_str); g_free(new_bpath);
431         // Zero-length subpaths
432         bpath = sp_svg_read_path("M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6");
433         path_str = sp_svg_write_path(bpath);
434         new_bpath = sp_svg_read_path(path_str);
435         TS_ASSERT(bpathEqual(bpath,new_bpath));
436         g_free(bpath); g_free(path_str); g_free(new_bpath);
437         // Floating-point
438         bpath = sp_svg_read_path("M .01,.02 L 0.04,0.02 L.04,.08L0.01,0.08 z""M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L04E-2,.08e0L1.0e-2,80e-3 z");
439         path_str = sp_svg_write_path(bpath);
440         new_bpath = sp_svg_read_path(path_str);
441         TS_ASSERT(bpathEqual(bpath, new_bpath, 1e-17));
442         g_free(bpath); g_free(path_str); g_free(new_bpath);
443     }
445     void testMinexpPrecision() {
446         NArtBpath * bpath;
447         char * path_str;
448         // Default values
449         prefs_set_int_attribute("options.svgoutput", "allowrelativecoordinates", 1);
450         prefs_set_int_attribute("options.svgoutput", "forcerepeatcommands", 0);
451         prefs_set_int_attribute("options.svgoutput", "numericprecision", 8);
452         prefs_set_int_attribute("options.svgoutput", "minimumexponent", -8);
453         bpath = sp_svg_read_path("M 123456781,1.23456781e-8 L 123456782,1.23456782e-8 L 123456785,1.23456785e-8 L 10123456400,1.23456785e-8 L 123456789,1.23456789e-8 L 123456789,101.234564e-8 L 123456789,1.23456789e-8");
454         path_str = sp_svg_write_path(bpath);
455         TS_ASSERT_RELATION( streq_rel , "m 123456780,1.2345678e-8 0,0 10,1e-15 9999999210,0 -9999999210,0 0,9.99999921e-7 0,-9.99999921e-7" , path_str );
456         g_free(bpath); g_free(path_str);
457     }
459 private:
460     bool bpathEqual(NArtBpath const * a, NArtBpath const * b, double eps = 1e-16) {
461         while(a->code != NR_END && b->code == a->code) {
462             switch(a->code) {
463             case NR_MOVETO:
464             case NR_MOVETO_OPEN:
465             case NR_LINETO:
466                 if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;
467                 break;
468             case NR_CURVETO:
469                 if (!Geom::are_near(a->x1,b->x1, eps) || !Geom::are_near(a->y1,b->y1, eps)) return false;
470                 if (!Geom::are_near(a->x2,b->x2, eps) || !Geom::are_near(a->y2,b->y2, eps)) return false;
471                 if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;
472                 break;
473             default:
474                 TS_FAIL("Unknown path code!");
475             }
476             a++;
477             b++;
478         }
479         return a->code == b->code;
480     }
481 };
484 /*
485   Local Variables:
486   mode:c++
487   c-file-style:"stroustrup"
488   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
489   indent-tabs-mode:nil
490   fill-column:99
491   End:
492 */
493 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :