]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/output-svg.scm
Add support for measures split across lines.
[lilypond.git] / scm / output-svg.scm
index 9004694a058d7e3b71c2dc12bfe9b2fe81c5d72e..a15a9d8ad0bc59432a8b69bf164017a56fa78ccf 100644 (file)
@@ -1,6 +1,6 @@
 ;;;; This file is part of LilyPond, the GNU music typesetter.
 ;;;;
-;;;; Copyright (C) 2002--2010 Jan Nieuwenhuizen <janneke@gnu.org>
+;;;; Copyright (C) 2002--2012 Jan Nieuwenhuizen <janneke@gnu.org>
 ;;;;                Patrick McCarty <pnorcks@gmail.com>
 ;;;;
 ;;;; LilyPond is free software: you can redistribute it and/or modify
@@ -29,6 +29,7 @@
   (guile)
   (ice-9 regex)
   (ice-9 format)
+  (ice-9 optargs)
   (lily)
   (srfi srfi-1)
   (srfi srfi-13))
                      (value (cdr x)))
                  (if (number? value)
                      (set! value (ly:format "~4f" value)))
-                 (format " ~s=\"~a\"" attr value)))
+                 (format #f " ~s=\"~a\"" attr value)))
              attributes-alist)))
 
 (define-public (eo entity . attributes-alist)
   "o = open"
-  (format "<~S~a>\n" entity (attributes attributes-alist)))
+  (format #f "<~S~a>\n" entity (attributes attributes-alist)))
 
 (define-public (eoc entity . attributes-alist)
-  " oc = open/close"
-  (format "<~S~a/>\n" entity (attributes attributes-alist)))
+  "oc = open/close"
+  (format #f "<~S~a/>\n" entity (attributes attributes-alist)))
 
 (define-public (ec entity)
   "c = close"
-  (format "</~S>\n" entity))
+  (format #f "</~S>\n" entity))
+
+(define (start-enclosing-id-node s)
+  (string-append "<g id=\"" s "\">\n"))
+
+(define (end-enclosing-id-node)
+  "</g>\n")
 
 (define-public (comment s)
   (string-append "<!-- " s " -->\n"))
@@ -85,7 +92,7 @@
   (define (helper lst)
     (if (null? lst)
        '()
-       (cons (format "~S ~S" (car lst) (- (cadr lst)))
+       (cons (format #f "~S ~S" (car lst) (- (cadr lst)))
              (helper (cddr lst)))))
 
   (string-join (helper lst) " "))
           (begin
             (set! path (apply dump-path d-attr-value
                                         font-scale
-                                        (list (cadr rest) (caddr rest))))
+                                        (list (caddr rest) (cadddr rest))))
             (set! next-horiz-adv (+ next-horiz-adv
                                     (car rest)))
             path))
            ""))))
 
 (define (extract-glyph-info all-glyphs glyph size)
-  (let* ((offsets (list-head glyph 3))
+  (let* ((offsets (list-head glyph 4))
         (glyph-name (car (reverse glyph))))
     (apply extract-glyph all-glyphs glyph-name size offsets)))
 
 ;;; stencil outputters
 ;;;
 
-(define (bezier-sandwich lst thick)
-  (let* ((first (list-tail lst 4))
-        (second (list-head lst 4)))
-    (entity 'path ""
-           '(stroke-linejoin . "round")
-           '(stroke-linecap . "round")
-           '(stroke . "currentColor")
-           '(fill . "currentColor")
-           `(stroke-width . ,thick)
-           `(d . ,(string-append (svg-bezier first #f)
-                                 (svg-bezier second #t))))))
-
 (define (char font i)
   (dispatch
    `(fontify ,font ,(entity 'tspan (char->entity (integer->char i))))))
 
 (define (dashed-line thick on off dx dy phase)
   (draw-line thick 0 0 dx dy
-            `(stroke-dasharray . ,(format "~a,~a" on off))))
+            `(stroke-dasharray . ,(format #f "~a,~a" on off))))
 
 (define (draw-line thick x1 y1 x2 y2 . alist)
   (apply entity 'line ""
                 (* (* x-radius x-radius)
                    (* (sin angle) (sin angle)))))))
   (let*
-    ((dummy (format #t "INFO XR ~a YR ~a SA ~a EA ~a\n" x-radius y-radius start-angle end-angle))
-     (new-start-angle (* PI-OVER-180 (angle-0-360 start-angle)))
+    ((new-start-angle (* PI-OVER-180 (angle-0-360 start-angle)))
      (start-radius (make-ellipse-radius x-radius y-radius new-start-angle))
      (new-end-angle (* PI-OVER-180 (angle-0-360 end-angle)))
      (end-radius (make-ellipse-radius x-radius y-radius new-end-angle))
      (x-end (- (* end-radius (cos new-end-angle))
                (* start-radius (cos new-start-angle))))
      (y-end (- (* end-radius (sin new-end-angle))
-               (* start-radius (sin new-start-angle))))
-     (dummy (format #t "INFO NSA ~a SR ~a NEA ~a ER ~a\n" new-start-angle start-radius new-end-angle end-radius)))
+               (* start-radius (sin new-start-angle)))))
    (if (and (< (abs x-end) epsilon) (< (abs y-end) epsilon))
     (entity
       'ellipse ""
                            (- (* start-radius (sin new-start-angle))))
                 "")))))))
 
-(define (connected-shape pointlist thick x-scale y-scale connect fill)
-  (entity
-    'path ""
-    `(fill . ,(if fill "currentColor" "none"))
-    `(stroke . "currentColor")
-    `(stroke-width . ,thick)
-    '(stroke-linejoin . "round")
-    '(stroke-linecap . "round")
-    (cons
-      'd
-      (ly:format
-        "M0 0~a ~a"
-        (string-concatenate
-          (map (lambda (x)
-                 (apply
-                   (if (eq? (length x) 6)
-                       (lambda (x1 x2 x3 x4 x5 x6)
-                         (ly:format "C~4f ~4f ~4f ~4f ~4f ~4f"
-                                    (* x1 x-scale)
-                                    (- (* x2 y-scale))
-                                    (* x3 x-scale)
-                                    (- (* x4 y-scale))
-                                    (* x5 x-scale)
-                                    (- (* x6 y-scale))))
-                       (lambda (x1 x2)
-                         (ly:format "L~4f ~4f"
-                                    (* x-scale x1)
-                                    (- (* y-scale x2)))))
-                   x))
-               pointlist))
-        (if connect "z " "")))))
-
 (define (embedded-svg string)
   string)
 
-(define (embedded-glyph-string font size cid glyphs)
+(define (embedded-glyph-string pango-font font size cid glyphs)
   (define path "")
   (if (= 1 (length glyphs))
       (set! path (music-string-to-path font size (car glyphs)))
   (set! next-horiz-adv 0.0)
   path)
 
-(define (woff-glyph-string font-name size cid? w-x-y-named-glyphs)
+(define (woff-glyph-string pango-font font-name size cid? w-h-x-y-named-glyphs)
   (let* ((name-style (font-name-style font-name))
         (family-designsize (regexp-exec (make-regexp "(.*)-([0-9]*)")
                                         font-name))
         (font (ly:paper-get-font paper `(((font-family . ,family)
                                           ,(if design-size
                                                `(design-size . design-size)))))))
-    (define (glyph-spec w x y g)
+    (define (glyph-spec w h x y g) ; h not used
       (let* ((charcode (ly:font-glyph-name-to-charcode font g))
             (char-lookup (format #f "&#~S;" charcode))
             (glyph-by-name (eoc 'altglyph `(glyphname . ,g)))
          (string-append glyph-by-name apparently-broken char-lookup)))))
 
     (string-join (map (lambda (x) (apply glyph-spec x))
-                     (reverse w-x-y-named-glyphs)) "\n")))
+                     (reverse w-h-x-y-named-glyphs)) "\n")))
 
 (define glyph-string
   (if (not (ly:get-option 'svg-woff)) embedded-glyph-string woff-glyph-string))
 (define (no-origin)
   "")
 
-(define (oval x-radius y-radius thick is-filled)
-  (let ((x-max x-radius)
-       (x-min (- x-radius))
-       (y-max y-radius)
-       (y-min (- y-radius)))
-    (entity
-      'path ""
-      '(stroke-linejoin . "round")
-      '(stroke-linecap . "round")
-      `(fill . ,(if is-filled "currentColor" "none"))
-      `(stroke . "currentColor")
-      `(stroke-width . ,thick)
-      `(d . ,(ly:format "M~4f ~4fC~4f ~4f ~4f ~4f ~4f ~4fS~4f ~4f ~4f ~4fz"
-                       x-max 0
-                       x-max y-max
-                       x-min y-max
-                       x-min 0
-                       x-max y-min
-                       x-max 0)))))
-
-(define (path thick commands)
+(define* (path thick commands #:optional (cap 'round) (join 'round) (fill? #f))
   (define (convert-path-exps exps)
     (if (pair? exps)
        (let*
                                  (closepath . z))
                                "")))
 
-         (cons (format "~a~a" svg-head (number-list->point args))
+         (cons (format #f "~a~a" svg-head (number-list->point args))
                (convert-path-exps (drop rest arity))))
        '()))
 
-  (entity 'path ""
-         `(stroke-width . ,thick)
-         '(stroke-linejoin . "round")
-         '(stroke-linecap . "round")
-         '(stroke . "currentColor")
-         '(fill . "none")
-         `(d . ,(apply string-append (convert-path-exps commands)))))
+  (let* ((line-cap-styles '(butt round square))
+        (line-join-styles '(miter round bevel))
+        (cap-style (if (not (memv cap line-cap-styles))
+                       (begin
+                         (ly:warning (_ "unknown line-cap-style: ~S")
+                                     (symbol->string cap))
+                         'round)
+                       cap))
+        (join-style (if (not (memv join line-join-styles))
+                        (begin
+                          (ly:warning (_ "unknown line-join-style: ~S")
+                                      (symbol->string join))
+                          'round)
+                        join)))
+    (entity 'path ""
+           `(stroke-width . ,thick)
+           `(stroke-linejoin . ,(symbol->string join-style))
+           `(stroke-linecap . ,(symbol->string cap-style))
+           '(stroke . "currentColor")
+           `(fill . ,(if fill? "currentColor" "none"))
+           `(d . ,(apply string-append (convert-path-exps commands))))))
 
 (define (placebox x y expr)
   (if (string-null? expr)
     `(points . ,(string-join
                  (map offset->point (ly:list->offsets '() coords))))))
 
-(define (repeat-slash width slope thickness)
-  (define (euclidean-length x y)
-    (sqrt (+ (* x x) (* y y))))
-  (let* ((x-width (euclidean-length thickness (/ thickness slope)))
-        (height (* width slope)))
-    (entity
-      'path ""
-      '(fill . "currentColor")
-      `(d . ,(ly:format "M0 0l~4f 0 ~4f ~4f ~4f 0z"
-                       x-width width (- height) (- x-width))))))
-
 (define (resetcolor)
   "</g>\n")
 
 (define (resetrotation ang x y)
   "</g>\n")
 
+(define (resetscale)
+  "</g>\n")
+
 (define (round-filled-box breapth width depth height blot-diameter)
   (entity
     'rect ""
     '(fill . "currentColor")))
 
 (define (setcolor r g b)
-  (format "<g color=\"rgb(~a%, ~a%, ~a%)\">\n"
+  (format #f "<g color=\"rgb(~a%, ~a%, ~a%)\">\n"
          (* 100 r) (* 100 g) (* 100 b)))
 
 ;; rotate around given point
   (ly:format "<g transform=\"rotate(~4f, ~4f, ~4f)\">\n"
             (- ang) x (- y)))
 
+(define (setscale x y)
+  (ly:format "<g transform=\"scale(~4f, ~4f)\">\n"
+            x y))
+
 (define (text font string)
   (dispatch `(fontify ,font ,(entity 'tspan (string->entities string)))))
 
    (ec 'a)))
 
 (define (utf-8-string pango-font-description string)
-  (dispatch `(fontify ,pango-font-description ,(entity 'tspan string))))
+  (let ((escaped-string (string-regexp-substitute
+                         "<" "&lt;"
+                         (string-regexp-substitute "&" "&amp;" string))))
+    (dispatch `(fontify ,pango-font-description
+                       ,(entity 'tspan escaped-string)))))