+(define-public empty-stencil (ly:make-stencil '() '(1 . -1) '(1 . -1)))
+(define-public point-stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
+
+(def-markup-command (stencil layout props stil) (ly:stencil?)
+ "Stencil as markup"
+ stil)
+
+(def-markup-command (draw-circle layout props radius thickness fill)
+ (number? number? boolean?)
+ "A circle of radius @var{radius}, thickness @var{thickness} and
+optionally filled."
+ (make-circle-stencil radius thickness fill))
+
+(def-markup-command (triangle layout props filled) (boolean?)
+ "A triangle, filled or not"
+ (let*
+ ((th (chain-assoc-get 'thickness props 0.1))
+ (size (chain-assoc-get 'font-size props 0))
+ (ex (* (magstep size)
+ 0.8
+ (chain-assoc-get 'baseline-skip props 2))))
+
+ (ly:make-stencil
+ `(polygon '(0.0 0.0
+ ,ex 0.0
+ ,(* 0.5 ex)
+ ,(* 0.86 ex))
+ ,th
+ ,filled)
+
+ (cons 0 ex)
+ (cons 0 (* .86 ex))
+ )))
+
+(def-markup-command (circle layout props arg) (markup?)
+ "Draw a circle around @var{arg}. Use @code{thickness},
+@code{circle-padding} and @code{font-size} properties to determine line
+thickness and padding around the markup."
+ (let* ((th (chain-assoc-get 'thickness props 0.1))
+ (size (chain-assoc-get 'font-size props 0))
+ (pad
+ (* (magstep size)
+ (chain-assoc-get 'circle-padding props 0.2)))
+ (m (interpret-markup layout props arg)))
+ (circle-stencil m th pad)))
+
+(def-markup-command (with-url layout props url arg) (string? markup?)
+ "Add a link to URL @var{url} around @var{arg}. This only works in
+the PDF backend."
+ (let* ((stil (interpret-markup layout props arg))
+ (xextent (ly:stencil-extent stil X))
+ (yextent (ly:stencil-extent stil Y))
+ (old-expr (ly:stencil-expr stil))
+ (url-expr (list 'url-link url `(quote ,xextent) `(quote ,yextent))))
+ (ly:stencil-add (ly:make-stencil url-expr xextent yextent) stil)))
+
+
+(define bbox-regexp
+ (make-regexp "%%BoundingBox: ([0-9-]+) ([0-9-]+) ([0-9-]+) ([0-9-]+)"))
+
+(define (get-postscript-bbox string)
+ "Extract the bbox from STRING, or return #f if not present."
+ (let*
+ ((match (regexp-exec bbox-regexp string)))
+
+ (if match
+ (map (lambda (x)
+ (string->number (match:substring match x)))
+ (cdr (iota 5)))
+
+ #f)))
+
+(def-markup-command (epsfile layout props file-name) (string?)
+ "Inline an EPS image. The image is scaled such that 10 PS units is
+one staff-space."
+
+ (if (ly:get-option 'safe)
+ (interpret-markup layout props "not allowed in safe")
+ (let*
+ ((contents (ly:gulp-file file-name))
+ (bbox (get-postscript-bbox contents))
+ (scaled-bbox
+ (if bbox
+ (map (lambda (x) (/ x 10)) bbox)
+ (begin
+ (ly:warn (_ "can't find bounding box of `~a'")
+ file-name)
+ '()))))
+
+
+ (if bbox
+
+ (ly:make-stencil
+ (list
+ 'embedded-ps
+ (string-append
+
+ ; adobe 5002.
+ "BeginEPSF "
+ "0.1 0.1 scale "
+ (format "\n%%BeginDocument: ~a\n" file-name)
+ contents
+ "%%EndDocument\n"
+ "EndEPSF\n"
+ ))
+ (cons (list-ref scaled-bbox 0) (list-ref scaled-bbox 2))
+ (cons (list-ref scaled-bbox 1) (list-ref scaled-bbox 3)))
+
+ (ly:make-stencil "" '(0 . 0) '(0 . 0))))))
+
+(def-markup-command (score layout props score) (ly:score?)
+ "Inline an image of music."
+ (let* ((output (ly:score-embedded-format score layout)))
+
+ (if (ly:music-output? output)
+ (ly:paper-system-stencil
+ (vector-ref (ly:paper-score-paper-systems output) 0))
+ (begin
+ (ly:warning (_"no systems found in \\score markup, does it have a \\layout block?"))
+ empty-stencil))))
+
+(def-markup-command (simple layout props str) (string?)
+ "A simple text string; @code{\\markup @{ foo @}} is equivalent with