@@ -144,20 +144,35 @@ def path(surface, node):
144
144
last_letter = None
145
145
string = normalize (string )
146
146
147
+ # Keep the current point because Cairo's get_current_point is not accurate
148
+ # enough. See https://github.com/Kozea/CairoSVG/issues/111.
149
+ if surface .context .has_current_point ():
150
+ current_point = surface .context .get_current_point ()
151
+ else :
152
+ surface .context .move_to (0 , 0 )
153
+ current_point = 0 , 0
154
+
147
155
while string :
148
156
string = string .strip ()
149
157
if string .split (' ' , 1 )[0 ] in PATH_LETTERS :
150
158
letter , string = (string + ' ' ).split (' ' , 1 )
151
159
if last_letter in (None , 'z' , 'Z' ) and letter not in 'mM' :
152
- node .vertices .append (surface .context .get_current_point ())
160
+ node .vertices .append (current_point )
161
+ first_path_point = current_point
153
162
elif letter == 'M' :
154
163
letter = 'L'
155
164
elif letter == 'm' :
156
165
letter = 'l'
157
166
167
+ if last_letter in (None , 'm' , 'M' , 'z' , 'Z' ):
168
+ first_path_point = None
169
+ if letter not in (None , 'm' , 'M' , 'z' , 'Z' ) and first_path_point is None :
170
+ first_path_point = current_point
171
+
158
172
if letter in 'aA' :
159
173
# Elliptic curve
160
- x1 , y1 = surface .context .get_current_point ()
174
+ surface .context .set_tolerance (0.00001 )
175
+ x1 , y1 = current_point
161
176
rx , ry , string = point (surface , string )
162
177
rotation , string = string .split (' ' , 1 )
163
178
rotation = radians (float (rotation ))
@@ -233,16 +248,18 @@ def path(surface, node):
233
248
surface .context .scale (1 , radii_ratio )
234
249
arc (xc , yc , rx , angle1 , angle2 )
235
250
surface .context .restore ()
251
+ current_point = current_point [0 ] + x3 , current_point [1 ] + y3
236
252
237
253
elif letter == 'c' :
238
254
# Relative curve
239
- x , y = surface . context . get_current_point ()
255
+ x , y = current_point
240
256
x1 , y1 , string = point (surface , string )
241
257
x2 , y2 , string = point (surface , string )
242
258
x3 , y3 , string = point (surface , string )
243
259
node .vertices .append ((
244
260
point_angle (x2 , y2 , x1 , y1 ), point_angle (x2 , y2 , x3 , y3 )))
245
261
surface .context .rel_curve_to (x1 , y1 , x2 , y2 , x3 , y3 )
262
+ current_point = current_point [0 ] + x3 , current_point [1 ] + y3
246
263
247
264
# Save absolute values for x and y, useful if next letter is s or S
248
265
x1 += x
@@ -260,50 +277,56 @@ def path(surface, node):
260
277
node .vertices .append ((
261
278
point_angle (x2 , y2 , x1 , y1 ), point_angle (x2 , y2 , x3 , y3 )))
262
279
surface .context .curve_to (x1 , y1 , x2 , y2 , x3 , y3 )
280
+ current_point = x3 , y3
263
281
264
282
elif letter == 'h' :
265
283
# Relative horizontal line
266
284
x , string = (string + ' ' ).split (' ' , 1 )
267
- old_x , old_y = surface . context . get_current_point ()
285
+ old_x , old_y = current_point
268
286
angle = 0 if size (surface , x , 'x' ) > 0 else pi
269
287
node .vertices .append ((pi - angle , angle ))
270
- surface .context .rel_line_to (size (surface , x , 'x' ), 0 )
288
+ x = size (surface , x , 'x' )
289
+ surface .context .rel_line_to (x , 0 )
290
+ current_point = current_point [0 ] + x , current_point [1 ]
271
291
272
292
elif letter == 'H' :
273
293
# Horizontal line
274
294
x , string = (string + ' ' ).split (' ' , 1 )
275
- old_x , old_y = surface . context . get_current_point ()
295
+ old_x , old_y = current_point
276
296
angle = 0 if size (surface , x , 'x' ) > old_x else pi
277
297
node .vertices .append ((pi - angle , angle ))
278
- surface .context .line_to (size (surface , x , 'x' ), old_y )
298
+ x = size (surface , x , 'x' )
299
+ surface .context .line_to (x , old_y )
300
+ current_point = x , current_point [1 ]
279
301
280
302
elif letter == 'l' :
281
303
# Relative straight line
282
304
x , y , string = point (surface , string )
283
305
angle = point_angle (0 , 0 , x , y )
284
306
node .vertices .append ((pi - angle , angle ))
285
307
surface .context .rel_line_to (x , y )
308
+ current_point = current_point [0 ] + x , current_point [1 ] + y
286
309
287
310
elif letter == 'L' :
288
311
# Straight line
289
312
x , y , string = point (surface , string )
290
- old_x , old_y = surface . context . get_current_point ()
313
+ old_x , old_y = current_point
291
314
angle = point_angle (old_x , old_y , x , y )
292
315
node .vertices .append ((pi - angle , angle ))
293
316
surface .context .line_to (x , y )
317
+ current_point = x , y
294
318
295
319
elif letter == 'm' :
296
320
# Current point relative move
297
321
x , y , string = point (surface , string )
298
- if surface .context .has_current_point ():
299
- surface .context .rel_move_to (x , y )
300
- else :
301
- surface .context .move_to (x , y )
322
+ surface .context .rel_move_to (x , y )
323
+ current_point = current_point [0 ] + x , current_point [1 ] + y
302
324
303
325
elif letter == 'M' :
304
326
# Current point move
305
327
x , y , string = point (surface , string )
306
328
surface .context .move_to (x , y )
329
+ current_point = x , y
307
330
308
331
elif letter == 'q' :
309
332
# Relative quadratic curve
@@ -314,27 +337,30 @@ def path(surface, node):
314
337
x1 , y1 , x2 , y2 , x3 , y3 )
315
338
surface .context .rel_curve_to (xq1 , yq1 , xq2 , yq2 , xq3 , yq3 )
316
339
node .vertices .append ((0 , 0 ))
340
+ current_point = current_point [0 ] + x3 , current_point [1 ] + y3
317
341
318
342
elif letter == 'Q' :
319
343
# Quadratic curve
320
- x1 , y1 = surface . context . get_current_point ()
344
+ x1 , y1 = current_point
321
345
x2 , y2 , string = point (surface , string )
322
346
x3 , y3 , string = point (surface , string )
323
347
xq1 , yq1 , xq2 , yq2 , xq3 , yq3 = quadratic_points (
324
348
x1 , y1 , x2 , y2 , x3 , y3 )
325
349
surface .context .curve_to (xq1 , yq1 , xq2 , yq2 , xq3 , yq3 )
326
350
node .vertices .append ((0 , 0 ))
351
+ current_point = x3 , y3
327
352
328
353
elif letter == 's' :
329
354
# Relative smooth curve
330
- x , y = surface . context . get_current_point ()
355
+ x , y = current_point
331
356
x1 = x3 - x2 if last_letter in 'csCS' else 0
332
357
y1 = y3 - y2 if last_letter in 'csCS' else 0
333
358
x2 , y2 , string = point (surface , string )
334
359
x3 , y3 , string = point (surface , string )
335
360
node .vertices .append ((
336
361
point_angle (x2 , y2 , x1 , y1 ), point_angle (x2 , y2 , x3 , y3 )))
337
362
surface .context .rel_curve_to (x1 , y1 , x2 , y2 , x3 , y3 )
363
+ current_point = current_point [0 ] + x3 , current_point [1 ] + y3
338
364
339
365
# Save absolute values for x and y, useful if next letter is s or S
340
366
x1 += x
@@ -346,14 +372,15 @@ def path(surface, node):
346
372
347
373
elif letter == 'S' :
348
374
# Smooth curve
349
- x , y = surface . context . get_current_point ()
375
+ x , y = current_point
350
376
x1 = x3 + (x3 - x2 ) if last_letter in 'csCS' else x
351
377
y1 = y3 + (y3 - y2 ) if last_letter in 'csCS' else y
352
378
x2 , y2 , string = point (surface , string )
353
379
x3 , y3 , string = point (surface , string )
354
380
node .vertices .append ((
355
381
point_angle (x2 , y2 , x1 , y1 ), point_angle (x2 , y2 , x3 , y3 )))
356
382
surface .context .curve_to (x1 , y1 , x2 , y2 , x3 , y3 )
383
+ current_point = x3 , y3
357
384
358
385
elif letter == 't' :
359
386
# Relative quadratic curve end
@@ -372,10 +399,11 @@ def path(surface, node):
372
399
x1 , y1 , x2 , y2 , x3 , y3 )
373
400
node .vertices .append ((0 , 0 ))
374
401
surface .context .rel_curve_to (xq1 , yq1 , xq2 , yq2 , xq3 , yq3 )
402
+ current_point = current_point [0 ] + x3 , current_point [1 ] + y3
375
403
376
404
elif letter == 'T' :
377
405
# Quadratic curve end
378
- abs_x , abs_y = surface . context . get_current_point ()
406
+ abs_x , abs_y = current_point
379
407
if last_letter not in 'QqTt' :
380
408
x2 , y2 , x3 , y3 = abs_x , abs_y , abs_x , abs_y
381
409
elif last_letter in 'qt' :
@@ -389,30 +417,36 @@ def path(surface, node):
389
417
x1 , y1 , x2 , y2 , x3 , y3 )
390
418
node .vertices .append ((0 , 0 ))
391
419
surface .context .curve_to (xq1 , yq1 , xq2 , yq2 , xq3 , yq3 )
420
+ current_point = x3 , y3
392
421
393
422
elif letter == 'v' :
394
423
# Relative vertical line
395
424
y , string = (string + ' ' ).split (' ' , 1 )
396
- old_x , old_y = surface . context . get_current_point ()
425
+ old_x , old_y = current_point
397
426
angle = pi / 2 if size (surface , y , 'y' ) > 0 else - pi / 2
398
427
node .vertices .append ((- angle , angle ))
399
- surface .context .rel_line_to (0 , size (surface , y , 'y' ))
428
+ y = size (surface , y , 'y' )
429
+ surface .context .rel_line_to (0 , y )
430
+ current_point = current_point [0 ], current_point [1 ] + y
400
431
401
432
elif letter == 'V' :
402
433
# Vertical line
403
434
y , string = (string + ' ' ).split (' ' , 1 )
404
- old_x , old_y = surface . context . get_current_point ()
435
+ old_x , old_y = current_point
405
436
angle = pi / 2 if size (surface , y , 'y' ) > 0 else - pi / 2
406
437
node .vertices .append ((- angle , angle ))
407
- surface .context .line_to (old_x , size (surface , y , 'y' ))
438
+ y = size (surface , y , 'y' )
439
+ surface .context .line_to (old_x , y )
440
+ current_point = current_point [0 ], y
408
441
409
442
elif letter in 'zZ' :
410
443
# End of path
411
444
node .vertices .append (None )
412
445
surface .context .close_path ()
446
+ current_point = first_path_point or (0 , 0 )
413
447
414
448
if letter not in 'zZ' :
415
- node .vertices .append (surface . context . get_current_point () )
449
+ node .vertices .append (current_point )
416
450
417
451
string = string .strip ()
418
452
last_letter = letter
0 commit comments