aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorFelix E. Klee2019-07-15 17:07:56 +0200
committerLars Ingebrigtsen2019-07-15 17:07:56 +0200
commitd6bc55ae2dc98c83e58a28e380ce4bcf2ed00bb3 (patch)
tree47e633d687d0bda97e8613c57bed4ab816e55d44 /lisp
parent3b6992118501d0a17b6817a91011f8e8dcdf8164 (diff)
downloademacs-d6bc55ae2dc98c83e58a28e380ce4bcf2ed00bb3.tar.gz
emacs-d6bc55ae2dc98c83e58a28e380ce4bcf2ed00bb3.zip
Add support for paths to svg.el
* doc/lispref/display.texi (SVG Images): Document svg-path, svg-clip-path and svg-node (bug#32359). * doc/lispref/display.texi (SVG Path Commands): New node. * lisp/svg.el (svg--plist-delete, svg--path-command-symbol) (svg--elliptical-arc-coordinates, svg--elliptical-arc-command) (svg--moveto-command, svg--closepath-command) (svg--lineto-command, svg--horizontal-lineto-command) (svg--vertical-lineto-command, svg--curveto-command) (svg--smooth-curveto-command) (svg--quadratic-bezier-curveto-command) (svg--smooth-quadratic-bezier-curveto-command) (svg--eval-path-command, svg-path, svg-clip-path, svg-node): New functions.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/svg.el148
1 files changed, 148 insertions, 0 deletions
diff --git a/lisp/svg.el b/lisp/svg.el
index 86b56a03d56..2ab56d3960d 100644
--- a/lisp/svg.el
+++ b/lisp/svg.el
@@ -3,6 +3,7 @@
3;; Copyright (C) 2014-2019 Free Software Foundation, Inc. 3;; Copyright (C) 2014-2019 Free Software Foundation, Inc.
4 4
5;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org> 5;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6;; Felix E. Klee <felix.klee@inka.de>
6;; Keywords: image 7;; Keywords: image
7;; Version: 1.0 8;; Version: 1.0
8;; Package-Requires: ((emacs "25")) 9;; Package-Requires: ((emacs "25"))
@@ -324,6 +325,153 @@ If the SVG is later changed, the image will also be updated."
324 "\\'"))))) 325 "\\'")))))
325 (when node (dom-remove-node svg node)))) 326 (when node (dom-remove-node svg node))))
326 327
328;; Function body copied from `org-plist-delete' in Emacs 26.1.
329(defun svg--plist-delete (plist property)
330 "Delete PROPERTY from PLIST.
331This is in contrast to merely setting it to 0."
332 (let (p)
333 (while plist
334 (if (not (eq property (car plist)))
335 (setq p (plist-put p (car plist) (nth 1 plist))))
336 (setq plist (cddr plist)))
337 p))
338
339(defun svg--path-command-symbol (command-symbol command-args)
340 (let ((char (symbol-name command-symbol))
341 (relative (if (plist-member command-args :relative)
342 (plist-get command-args :relative)
343 (plist-get command-args :default-relative))))
344 (intern (if relative (downcase char) (upcase char)))))
345
346(defun svg--elliptical-arc-coordinates
347 (rx ry x y &rest args)
348 (list
349 rx ry
350 (or (plist-get args :x-axis-rotation) 0)
351 (if (plist-get args :large-arc) 1 0)
352 (if (plist-get args :sweep) 1 0)
353 x y))
354
355(defun svg--elliptical-arc-command (coordinates-list &rest args)
356 (cons
357 (svg--path-command-symbol 'a args)
358 (apply 'append
359 (mapcar
360 (lambda (coordinates)
361 (apply 'svg--elliptical-arc-coordinates
362 coordinates))
363 coordinates-list))))
364
365(defun svg--moveto-command (coordinates-list &rest args)
366 (cons
367 (svg--path-command-symbol 'm args)
368 (apply 'append
369 (mapcar
370 (lambda (coordinates)
371 (list (car coordinates) (cdr coordinates)))
372 coordinates-list))))
373
374(defun svg--closepath-command (&rest args)
375 (list (svg--path-command-symbol 'z args)))
376
377(defun svg--lineto-command (coordinates-list &rest args)
378 (cons
379 (svg--path-command-symbol 'l args)
380 (apply 'append
381 (mapcar
382 (lambda (coordinates)
383 (list (car coordinates) (cdr coordinates)))
384 coordinates-list))))
385
386(defun svg--horizontal-lineto-command (coordinate-list &rest args)
387 (cons
388 (svg--path-command-symbol 'h args)
389 coordinate-list))
390
391(defun svg--vertical-lineto-command (coordinate-list &rest args)
392 (cons
393 (svg--path-command-symbol 'v args)
394 coordinate-list))
395
396(defun svg--curveto-command (coordinates-list &rest args)
397 (cons
398 (svg--path-command-symbol 'c args)
399 (apply 'append coordinates-list)))
400
401(defun svg--smooth-curveto-command (coordinates-list &rest args)
402 (cons
403 (svg--path-command-symbol 's args)
404 (apply 'append coordinates-list)))
405
406(defun svg--quadratic-bezier-curveto-command (coordinates-list
407 &rest args)
408 (cons
409 (svg--path-command-symbol 'q args)
410 (apply 'append coordinates-list)))
411
412(defun svg--smooth-quadratic-bezier-curveto-command (coordinates-list
413 &rest args)
414 (cons
415 (svg--path-command-symbol 't args)
416 (apply 'append coordinates-list)))
417
418(defun svg--eval-path-command (command default-relative)
419 (cl-letf
420 (((symbol-function 'moveto) #'svg--moveto-command)
421 ((symbol-function 'closepath) #'svg--closepath-command)
422 ((symbol-function 'lineto) #'svg--lineto-command)
423 ((symbol-function 'horizontal-lineto)
424 #'svg--horizontal-lineto-command)
425 ((symbol-function 'vertical-lineto)
426 #'svg--vertical-lineto-command)
427 ((symbol-function 'curveto) #'svg--curveto-command)
428 ((symbol-function 'smooth-curveto)
429 #'svg--smooth-curveto-command)
430 ((symbol-function 'quadratic-bezier-curveto)
431 #'svg--quadratic-bezier-curveto-command)
432 ((symbol-function 'smooth-quadratic-bezier-curveto)
433 #'svg--smooth-quadratic-bezier-curveto-command)
434 ((symbol-function 'elliptical-arc)
435 #'svg--elliptical-arc-command)
436 (extended-command (append command (list :default-relative
437 default-relative))))
438 (mapconcat 'prin1-to-string (apply extended-command) " ")))
439
440(defun svg-path (svg commands &rest args)
441 "Add the outline of a shape to SVG according to COMMANDS.
442Coordinates by default are absolute. ARGS is a plist of
443modifiers. If :relative is t, then coordinates are relative to
444the last position, or -- initially -- to the origin."
445 (let* ((default-relative (plist-get args :relative))
446 (stripped-args (svg--plist-delete args :relative))
447 (d (mapconcat 'identity
448 (mapcar
449 (lambda (command)
450 (svg--eval-path-command command
451 default-relative))
452 commands) " ")))
453 (svg--append
454 svg
455 (dom-node 'path
456 `((d . ,d)
457 ,@(svg--arguments svg stripped-args))))))
458
459(defun svg-clip-path (svg &rest args)
460 "Add a clipping path to SVG, where ARGS is a plist of modifiers.
461If applied to a shape via the :clip-path property, parts of that
462shape which lie outside of the clipping path are not drawn."
463 (let ((new-dom-node (dom-node 'clipPath
464 `(,@(svg--arguments svg args)))))
465 (svg--append svg new-dom-node)
466 new-dom-node))
467
468(defun svg-node (svg tag &rest args)
469 "Add the custom node TAG to SVG."
470 (let ((new-dom-node (dom-node tag
471 `(,@(svg--arguments svg args)))))
472 (svg--append svg new-dom-node)
473 new-dom-node))
474
327(provide 'svg) 475(provide 'svg)
328 476
329;;; svg.el ends here 477;;; svg.el ends here