diff options
author | Lars Ingebrigtsen <larsi@gnus.org> | 2019-07-31 22:29:29 +0200 |
---|---|---|
committer | Lars Ingebrigtsen <larsi@gnus.org> | 2019-07-31 22:29:29 +0200 |
commit | 5f78e81af0c2648391f26602189c565627e08218 (patch) | |
tree | 3a75ad5cb65460b4c492323050fb8059877876e3 /lisp/svg.el | |
parent | ee7baca4fa96d4e1ad6bd9ad055d92f435b7eaa6 (diff) | |
download | emacs-5f78e81af0c2648391f26602189c565627e08218.tar.gz |
Revert "Revert "Add support for paths to svg.el""
This reverts commit 0a2461be9edb218bf9ca56156d8966a2421f13a7.
Copyright paperwork is now in place, so the patch mistakenly applied
can now be re-applied.
Diffstat (limited to 'lisp/svg.el')
-rw-r--r-- | lisp/svg.el | 148 |
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 @@ ;; Copyright (C) 2014-2019 Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org> +;; Felix E. Klee <felix.klee@inka.de> ;; Keywords: image ;; Version: 1.0 ;; Package-Requires: ((emacs "25")) @@ -324,6 +325,153 @@ If the SVG is later changed, the image will also be updated." "\\'"))))) (when node (dom-remove-node svg node)))) +;; Function body copied from `org-plist-delete' in Emacs 26.1. +(defun svg--plist-delete (plist property) + "Delete PROPERTY from PLIST. +This is in contrast to merely setting it to 0." + (let (p) + (while plist + (if (not (eq property (car plist))) + (setq p (plist-put p (car plist) (nth 1 plist)))) + (setq plist (cddr plist))) + p)) + +(defun svg--path-command-symbol (command-symbol command-args) + (let ((char (symbol-name command-symbol)) + (relative (if (plist-member command-args :relative) + (plist-get command-args :relative) + (plist-get command-args :default-relative)))) + (intern (if relative (downcase char) (upcase char))))) + +(defun svg--elliptical-arc-coordinates + (rx ry x y &rest args) + (list + rx ry + (or (plist-get args :x-axis-rotation) 0) + (if (plist-get args :large-arc) 1 0) + (if (plist-get args :sweep) 1 0) + x y)) + +(defun svg--elliptical-arc-command (coordinates-list &rest args) + (cons + (svg--path-command-symbol 'a args) + (apply 'append + (mapcar + (lambda (coordinates) + (apply 'svg--elliptical-arc-coordinates + coordinates)) + coordinates-list)))) + +(defun svg--moveto-command (coordinates-list &rest args) + (cons + (svg--path-command-symbol 'm args) + (apply 'append + (mapcar + (lambda (coordinates) + (list (car coordinates) (cdr coordinates))) + coordinates-list)))) + +(defun svg--closepath-command (&rest args) + (list (svg--path-command-symbol 'z args))) + +(defun svg--lineto-command (coordinates-list &rest args) + (cons + (svg--path-command-symbol 'l args) + (apply 'append + (mapcar + (lambda (coordinates) + (list (car coordinates) (cdr coordinates))) + coordinates-list)))) + +(defun svg--horizontal-lineto-command (coordinate-list &rest args) + (cons + (svg--path-command-symbol 'h args) + coordinate-list)) + +(defun svg--vertical-lineto-command (coordinate-list &rest args) + (cons + (svg--path-command-symbol 'v args) + coordinate-list)) + +(defun svg--curveto-command (coordinates-list &rest args) + (cons + (svg--path-command-symbol 'c args) + (apply 'append coordinates-list))) + +(defun svg--smooth-curveto-command (coordinates-list &rest args) + (cons + (svg--path-command-symbol 's args) + (apply 'append coordinates-list))) + +(defun svg--quadratic-bezier-curveto-command (coordinates-list + &rest args) + (cons + (svg--path-command-symbol 'q args) + (apply 'append coordinates-list))) + +(defun svg--smooth-quadratic-bezier-curveto-command (coordinates-list + &rest args) + (cons + (svg--path-command-symbol 't args) + (apply 'append coordinates-list))) + +(defun svg--eval-path-command (command default-relative) + (cl-letf + (((symbol-function 'moveto) #'svg--moveto-command) + ((symbol-function 'closepath) #'svg--closepath-command) + ((symbol-function 'lineto) #'svg--lineto-command) + ((symbol-function 'horizontal-lineto) + #'svg--horizontal-lineto-command) + ((symbol-function 'vertical-lineto) + #'svg--vertical-lineto-command) + ((symbol-function 'curveto) #'svg--curveto-command) + ((symbol-function 'smooth-curveto) + #'svg--smooth-curveto-command) + ((symbol-function 'quadratic-bezier-curveto) + #'svg--quadratic-bezier-curveto-command) + ((symbol-function 'smooth-quadratic-bezier-curveto) + #'svg--smooth-quadratic-bezier-curveto-command) + ((symbol-function 'elliptical-arc) + #'svg--elliptical-arc-command) + (extended-command (append command (list :default-relative + default-relative)))) + (mapconcat 'prin1-to-string (apply extended-command) " "))) + +(defun svg-path (svg commands &rest args) + "Add the outline of a shape to SVG according to COMMANDS. +Coordinates by default are absolute. ARGS is a plist of +modifiers. If :relative is t, then coordinates are relative to +the last position, or -- initially -- to the origin." + (let* ((default-relative (plist-get args :relative)) + (stripped-args (svg--plist-delete args :relative)) + (d (mapconcat 'identity + (mapcar + (lambda (command) + (svg--eval-path-command command + default-relative)) + commands) " "))) + (svg--append + svg + (dom-node 'path + `((d . ,d) + ,@(svg--arguments svg stripped-args)))))) + +(defun svg-clip-path (svg &rest args) + "Add a clipping path to SVG, where ARGS is a plist of modifiers. +If applied to a shape via the :clip-path property, parts of that +shape which lie outside of the clipping path are not drawn." + (let ((new-dom-node (dom-node 'clipPath + `(,@(svg--arguments svg args))))) + (svg--append svg new-dom-node) + new-dom-node)) + +(defun svg-node (svg tag &rest args) + "Add the custom node TAG to SVG." + (let ((new-dom-node (dom-node tag + `(,@(svg--arguments svg args))))) + (svg--append svg new-dom-node) + new-dom-node)) + (provide 'svg) ;;; svg.el ends here |