]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/stencil-integral.cc
Doc-es: various updates.
[lilypond.git] / lily / stencil-integral.cc
index 0f1f14ff50485e09ff3933cc6db261ec6a7ab17e..b44258b6b1973c19d117626ba769a232467dd7e4 100644 (file)
@@ -34,7 +34,6 @@ when this transforms a point (x,y), the point is written as matrix:
 */
 
 #include <pango/pango-matrix.h>
-#include <complex>
 #include "box.hh"
 #include "bezier.hh"
 #include "dimensions.hh"
@@ -60,7 +59,9 @@ using namespace std;
 
 Real QUANTIZATION_UNIT = 0.2;
 
-void create_path_cap (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, Offset pt, Real rad, Real slope, Direction d);
+void create_path_cap (vector<Box> &boxes,
+                      vector<Drul_array<Offset> > &buildings,
+                      PangoMatrix trans, Offset pt, Real rad, Offset dir);
 
 struct Transform_matrix_and_expression
 {
@@ -113,7 +114,7 @@ get_number_list (SCM l)
       if (scm_is_number (scm_car (l)))
         return l;
       SCM res = get_number_list (scm_car (l));
-      if (res == SCM_BOOL_F)
+      if (scm_is_false (res))
         return get_number_list (scm_cdr (l));
       return res;
     }
@@ -129,33 +130,31 @@ get_path_list (SCM l)
 {
   if (scm_is_pair (l))
     {
-      if (scm_memv (scm_car (l),
-                    scm_list_n (ly_symbol2scm ("moveto"),
-                                ly_symbol2scm ("rmoveto"),
-                                ly_symbol2scm ("lineto"),
-                                ly_symbol2scm ("rlineto"),
-                                ly_symbol2scm ("curveto"),
-                                ly_symbol2scm ("rcurveto"),
-                                ly_symbol2scm ("closepath"),
-                                SCM_UNDEFINED))
-          != SCM_BOOL_F)
+      if (scm_is_true (scm_memv (scm_car (l),
+                                 scm_list_n (ly_symbol2scm ("moveto"),
+                                             ly_symbol2scm ("rmoveto"),
+                                             ly_symbol2scm ("lineto"),
+                                             ly_symbol2scm ("rlineto"),
+                                             ly_symbol2scm ("curveto"),
+                                             ly_symbol2scm ("rcurveto"),
+                                             ly_symbol2scm ("closepath"),
+                                             SCM_UNDEFINED))))
         return l;
       SCM res = get_path_list (scm_car (l));
-      if (res == SCM_BOOL_F)
+      if (scm_is_false (res))
         return get_path_list (scm_cdr (l));
       return res;
     }
   return SCM_BOOL_F;
 }
 
-Real
-perpendicular_slope (Real s)
+// Gets an orthogonal vector with same size to orig, pointing left
+// (in the complex domain, a multiplication by i)
+
+Offset
+get_normal (Offset orig)
 {
-  if (s == 0.0)
-    return infinity_f;
-  if (s == infinity_f)
-    return 0.0;
-  return -1.0 / s;
+  return Offset (-orig[Y_AXIS], orig[X_AXIS]);
 }
 
 //// END UTILITY FUNCTIONS
@@ -181,7 +180,7 @@ make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
   Real x1 = robust_scm2double (scm_car (expr), 0.0);
   expr = scm_cdr (expr);
   Real y1 = robust_scm2double (scm_car (expr), 0.0);
-  Real slope = x1 == x0 ? infinity_f : (y1 - y0) / (x1 - x0);
+
   //////////////////////
   if (x1 < x0)
     {
@@ -190,11 +189,12 @@ make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
     }
   Offset left (x0, y0);
   Offset right (x1, y1);
-  Direction d = DOWN;
-  do
+  Offset dir = (right - left).direction ();
+  for (DOWN_and_UP (d))
     {
-      Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (slope), thick / 2, d);
-      Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slope), thick / 2, d);
+      Offset outward = d * get_normal ((thick / 2) * dir);
+      Offset inter_l = left + outward;
+      Offset inter_r = right + outward;
       pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXIS]);
       pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXIS]);
       if ((inter_l[X_AXIS] == inter_r[X_AXIS]) || (inter_l[Y_AXIS] == inter_r[Y_AXIS]))
@@ -208,11 +208,7 @@ make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
         buildings.push_back (Drul_array<Offset> (inter_l, inter_r));
       else
         {
-          Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (slope), thick / 2, d);
-          Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slope), thick / 2, d);
-          pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXIS]);
-          pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXIS]);
-          Real length = sqrt (((inter_l[X_AXIS] - inter_r[X_AXIS]) * (inter_l[X_AXIS] - inter_r[X_AXIS])) + ((inter_l[Y_AXIS] - inter_r[Y_AXIS]) * (inter_l[Y_AXIS] - inter_r[Y_AXIS])));
+          Real length = (inter_l - inter_r).length ();
 
           vsize passes = (vsize) ((length * 2) + 1);
           vector<Offset> points;
@@ -221,7 +217,7 @@ make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
             {
               Offset pt (linear_map (x0, x1, 0, passes, i),
                          linear_map (y0, y1, 0, passes, i));
-              Offset inter = get_point_in_y_direction (pt, perpendicular_slope (slope), thick / 2, d);
+              Offset inter = pt + outward;
               pango_matrix_transform_point (&trans, &inter[X_AXIS], &inter[Y_AXIS]);
               points.push_back (inter);
             }
@@ -234,7 +230,6 @@ make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
             }
         }
     }
-  while (flip (&d) != DOWN);
 
   if (thick > 0.0)
     {
@@ -242,29 +237,30 @@ make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
       create_path_cap (boxes,
                        buildings,
                        trans,
-                       Offset (x0, y0),
+                       left,
                        thick / 2,
-                       perpendicular_slope (slope),
-                       Direction (sign (slope)));
+                       -dir);
 
       // end line cap
       create_path_cap (boxes,
                        buildings,
                        trans,
-                       Offset (x1, y1),
+                       right,
                        thick / 2,
-                       perpendicular_slope (slope),
-                       Direction (sign (-slope)));
+                       dir);
     }
 }
 
 void
-make_partial_ellipse_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr)
+make_partial_ellipse_boxes (vector<Box> &boxes,
+                            vector<Drul_array<Offset> > &buildings,
+                            PangoMatrix trans, SCM expr)
 {
   Real x_rad = robust_scm2double (scm_car (expr), 0.0);
   expr = scm_cdr (expr);
   Real y_rad = robust_scm2double (scm_car (expr), 0.0);
   expr = scm_cdr (expr);
+  Offset rad (x_rad, y_rad);
   Real start = robust_scm2double (scm_car (expr), 0.0);
   expr = scm_cdr (expr);
   Real end = robust_scm2double (scm_car (expr), 0.0);
@@ -275,83 +271,66 @@ make_partial_ellipse_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &bui
   expr = scm_cdr (expr);
   bool fill = to_boolean (scm_car (expr));
   //////////////////////
-  start = M_PI * start / 180;
-  end = M_PI * end / 180;
   if (end == start)
-    end += (2 * M_PI);
-  complex<Real> sunit = polar (1.0, start);
-  complex<Real> eunit = polar (1.0, end);
-  Offset sp (real (sunit) * x_rad, imag (sunit) * y_rad);
-  Offset ep (real (eunit) * x_rad, imag (eunit) * y_rad);
+    end += 360;
+  Offset sp (offset_directed (start).scale (rad));
+  Offset ep (offset_directed (end).scale (rad));
   //////////////////////
   Drul_array<vector<Offset> > points;
-  Direction d = DOWN;
   int quantization = max (1, (int) (((x_rad * trans.xx) + (y_rad * trans.yy)) * M_PI / QUANTIZATION_UNIT));
-  do
+  for (DOWN_and_UP (d))
     {
-      for (vsize i = 0; i < 1 + quantization; i++)
+      for (vsize i = 0; i < 1 + (vsize) quantization; i++)
         {
           Real ang = linear_map (start, end, 0, quantization, i);
-          complex<Real> coord = polar (1.0, ang);
-          Offset pt (real (coord) * x_rad,
-                     imag (coord) * y_rad);
-          Real slope = pt[Y_AXIS] / pt[X_AXIS];
-          Offset inter = get_point_in_y_direction (pt, perpendicular_slope (slope), th / 2, d);
+          Offset pt (offset_directed (ang).scale (rad));
+          Offset inter = pt + d * get_normal ((th/2) * pt.direction ());
           pango_matrix_transform_point (&trans, &inter[X_AXIS], &inter[Y_AXIS]);
           points[d].push_back (inter);
         }
     }
-  while (flip (&d) != DOWN);
 
   for (vsize i = 0; i < points[DOWN].size () - 1; i++)
     {
       Box b;
-      do
+      for (DOWN_and_UP (d))
         {
           b.add_point (points[d][i]);
           b.add_point (points[d][i + 1]);
         }
-      while (flip (&d) != DOWN);
       boxes.push_back (b);
     }
 
   if (connect || fill)
     {
-      make_draw_line_boxes (boxes, buildings, trans, scm_list_5 (scm_from_double (th),
-                                                                 scm_from_double (sp[X_AXIS]),
-                                                                 scm_from_double (sp[Y_AXIS]),
-                                                                 scm_from_double (ep[X_AXIS]),
-                                                                 scm_from_double (ep[Y_AXIS])),
+      make_draw_line_boxes (boxes, buildings, trans,
+                            scm_list_5 (scm_from_double (th),
+                                        scm_from_double (sp[X_AXIS]),
+                                        scm_from_double (sp[Y_AXIS]),
+                                        scm_from_double (ep[X_AXIS]),
+                                        scm_from_double (ep[Y_AXIS])),
                             false);
     }
 
   if (th > 0.0)
     {
       // beg line cap
-      complex<Real> coord = polar (1.0, start);
-      Offset pt (real (coord) * x_rad,
-                 imag (coord) * y_rad);
-      Real slope = pt[Y_AXIS] / pt[X_AXIS];
+      Offset pt (offset_directed (start).scale (rad));
       create_path_cap (boxes,
                        buildings,
                        trans,
                        pt,
                        th / 2,
-                       perpendicular_slope (slope),
-                       Direction (sign (slope)));
+                       -get_normal (pt));
 
       // end line cap
-      coord = polar (1.0, start);
-      pt = Offset (real (coord) * x_rad,
-                   imag (coord) * y_rad);
-      slope = pt[Y_AXIS] / pt[X_AXIS];
+      pt = offset_directed (end).scale (rad);
       create_path_cap (boxes,
                        buildings,
                        trans,
                        pt,
                        th / 2,
-                       perpendicular_slope (slope),
-                       Direction (sign (-slope)));
+                       get_normal (pt));
     }
 }
 
@@ -380,26 +359,18 @@ make_round_filled_box_boxes (vector<Box> &boxes, PangoMatrix trans, SCM expr)
 }
 
 void
-create_path_cap (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, Offset pt, Real rad, Real slope, Direction d)
+create_path_cap (vector<Box> &boxes,
+                 vector<Drul_array<Offset> > &buildings,
+                 PangoMatrix trans, Offset pt, Real rad, Offset dir)
 {
-  Real angle = atan (slope) * 180 / M_PI;
-  Real other = angle > 180 ? angle - 180 : angle + 180;
-  if (angle < other)
-    {
-      Real holder = other;
-      other = angle;
-      angle = holder;
-    }
-  other = (slope >= 0 && d == DOWN) || (slope < 0 && d == UP)
-          ? other + 360.0
-          : other;
+  Real angle = dir.angle_degrees ();
   PangoMatrix new_trans (trans);
   pango_matrix_translate (&new_trans, pt[X_AXIS], pt[Y_AXIS]);
   make_partial_ellipse_boxes (boxes, buildings, new_trans,
                               scm_list_n (scm_from_double (rad),
                                           scm_from_double (rad),
-                                          scm_from_double (angle),
-                                          scm_from_double (other),
+                                          scm_from_double (angle-90.01),
+                                          scm_from_double (angle+90.01),
                                           scm_from_double (0.0),
                                           SCM_BOOL_F,
                                           SCM_BOOL_F,
@@ -407,7 +378,9 @@ create_path_cap (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, Pan
 }
 
 void
-make_draw_bezier_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr)
+make_draw_bezier_boxes (vector<Box> &boxes,
+                        vector<Drul_array<Offset> > &buildings,
+                        PangoMatrix trans, SCM expr)
 {
   Real th = robust_scm2double (scm_car (expr), 0.0);
   expr = scm_cdr (expr);
@@ -442,77 +415,66 @@ make_draw_bezier_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildin
   pango_matrix_transform_point (&trans, &temp3[X_AXIS], &temp3[Y_AXIS]);
   //////////////////////
   Drul_array<vector<Offset> > points;
-  Direction d = DOWN;
   int quantization = int (((temp1 - temp0).length ()
                            + (temp2 - temp1).length ()
                            + (temp3 - temp2).length ())
                           / QUANTIZATION_UNIT);
-  do
+  for (DOWN_and_UP (d))
     {
-      Offset first = get_point_in_y_direction (curve.control_[0], perpendicular_slope (curve.slope_at_point (0.0)), th / 2, d);
+      Offset first = curve.control_[0]
+        + d * get_normal ((th / 2) * curve.dir_at_point (0.0));
       pango_matrix_transform_point (&trans, &first[X_AXIS], &first[Y_AXIS]);
       points[d].push_back (first);
-      for (vsize i = 1; i < quantization; i++)
+      for (vsize i = 1; i < (vsize) quantization; i++)
         {
           Real pt = (i * 1.0) / quantization;
-          Offset inter = get_point_in_y_direction (curve.curve_point (pt), perpendicular_slope (curve.slope_at_point (pt)), th / 2, d);
+          Offset inter = curve.curve_point (pt)
+            + d * get_normal ((th / 2) *curve.dir_at_point (pt));
           pango_matrix_transform_point (&trans, &inter[X_AXIS], &inter[Y_AXIS]);
           points[d].push_back (inter);
         }
-      Offset last = get_point_in_y_direction (curve.control_[3], curve.slope_at_point (1.0), th / 2, d);
+      Offset last = curve.control_[3]
+        + d * get_normal ((th / 2) * curve.dir_at_point (1.0));
       pango_matrix_transform_point (&trans, &last[X_AXIS], &last[Y_AXIS]);
       points[d].push_back (last);
     }
-  while (flip (&d) != DOWN);
 
   for (vsize i = 0; i < points[DOWN].size () - 1; i++)
     {
       Box b;
-      do
+      for (DOWN_and_UP (d))
         {
           b.add_point (points[d][i]);
           b.add_point (points[d][i + 1]);
         }
-      while (flip (&d) != DOWN);
       boxes.push_back (b);
     }
 
-  // beg line cap
   if (th >= 0)
     {
-      Real slope = curve.slope_at_point (0.0);
-      d = Direction (sign (slope == 0.0 || abs (slope) == infinity_f
-                           ? curve.slope_at_point (0.0001)
-                           : slope));
-
+      // beg line cap
       create_path_cap (boxes,
                        buildings,
                        trans,
                        curve.control_[0],
                        th / 2,
-                       perpendicular_slope (curve.slope_at_point (0.0)),
-                       d);
+                       -curve.dir_at_point (0.0));
 
       // end line cap
-      slope = curve.slope_at_point (1.0);
-      d = Direction (sign (slope == 0.0 || abs (slope) == infinity_f
-                           ? curve.slope_at_point (0.9999)
-                           : slope));
-
       create_path_cap (boxes,
                        buildings,
                        trans,
                        curve.control_[3],
                        th / 2,
-                       perpendicular_slope (curve.slope_at_point (1.0)),
-                       d);
+                       curve.dir_at_point (1.0));
     }
 }
 
 /*
   converts a path into lists of 4 (line) or 8 (curve) absolute coordinates
   for example:
-  '(moveto 1 2 lineto 3 4 rlineto -1 -1 curveto 3 3 5 5 6 6 rcurveto -1 -1 -1 -1 -1 -1 closepath)
+  '(moveto 1 2 lineto 3 4 rlineto -1 -1 curveto
+    3 3 5 5 6 6 rcurveto -1 -1 -1 -1 -1 -1 closepath)
   becomes
   '((1 2 3 4)
     (3 4 2 3)
@@ -530,8 +492,8 @@ all_commands_to_absolute_and_group (SCM expr)
   bool first = true;
   while (scm_is_pair (expr))
     {
-      if (scm_car (expr) == ly_symbol2scm ("moveto")
-          || (scm_car (expr) == ly_symbol2scm ("rmoveto") && first))
+      if (scm_is_eq (scm_car (expr), ly_symbol2scm ("moveto"))
+          || (scm_is_eq (scm_car (expr), ly_symbol2scm ("rmoveto")) && first))
         {
           Real x = robust_scm2double (scm_cadr (expr), 0.0);
           Real y = robust_scm2double (scm_caddr (expr), 0.0);
@@ -539,7 +501,7 @@ all_commands_to_absolute_and_group (SCM expr)
           current = start;
           expr = scm_cdddr (expr);
         }
-      if (scm_car (expr) == ly_symbol2scm ("rmoveto"))
+      if (scm_is_eq (scm_car (expr), ly_symbol2scm ("rmoveto")))
         {
           Real x = robust_scm2double (scm_cadr (expr), 0.0);
           Real y = robust_scm2double (scm_caddr (expr), 0.0);
@@ -547,7 +509,7 @@ all_commands_to_absolute_and_group (SCM expr)
           current = start;
           expr = scm_cdddr (expr);
         }
-      else if (scm_car (expr) == ly_symbol2scm ("lineto"))
+      else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("lineto")))
         {
           Real x = robust_scm2double (scm_cadr (expr), 0.0);
           Real y = robust_scm2double (scm_caddr (expr), 0.0);
@@ -559,7 +521,7 @@ all_commands_to_absolute_and_group (SCM expr)
           current = Offset (x, y);
           expr = scm_cdddr (expr);
         }
-      else if (scm_car (expr) == ly_symbol2scm ("rlineto"))
+      else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("rlineto")))
         {
           Real x = robust_scm2double (scm_cadr (expr), 0.0);
           Real y = robust_scm2double (scm_caddr (expr), 0.0);
@@ -571,7 +533,7 @@ all_commands_to_absolute_and_group (SCM expr)
           current = (Offset (x, y) + current);
           expr = scm_cdddr (expr);
         }
-      else if (scm_car (expr) == ly_symbol2scm ("curveto"))
+      else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("curveto")))
         {
           Real x1 = robust_scm2double (scm_cadr (expr), 0.0);
           expr = scm_cddr (expr);
@@ -597,7 +559,7 @@ all_commands_to_absolute_and_group (SCM expr)
                           out);
           current = Offset (x3, y3);
         }
-      else if (scm_car (expr) == ly_symbol2scm ("rcurveto"))
+      else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("rcurveto")))
         {
           Real x1 = robust_scm2double (scm_cadr (expr), 0.0);
           expr = scm_cddr (expr);
@@ -623,9 +585,10 @@ all_commands_to_absolute_and_group (SCM expr)
                           out);
           current = (Offset (x3, y3) + current);
         }
-      else if (scm_car (expr) == ly_symbol2scm ("closepath"))
+      else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("closepath")))
         {
-          if ((current[X_AXIS] != start[X_AXIS]) || (current[Y_AXIS] != start[Y_AXIS]))
+          if ((current[X_AXIS] != start[X_AXIS])
+              || (current[Y_AXIS] != start[Y_AXIS]))
             {
               out = scm_cons (scm_list_4 (scm_from_double (current[X_AXIS]),
                                           scm_from_double (current[Y_AXIS]),
@@ -647,7 +610,9 @@ all_commands_to_absolute_and_group (SCM expr)
 }
 
 void
-internal_make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr, bool use_building)
+internal_make_path_boxes (vector<Box> &boxes,
+                          vector<Drul_array<Offset> > &buildings,
+                          PangoMatrix trans, SCM expr, bool use_building)
 {
   SCM blot = scm_car (expr);
   expr = scm_cdr (expr);
@@ -663,13 +628,17 @@ internal_make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &build
 }
 
 void
-make_path_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr)
+make_path_boxes (vector<Box> &boxes,
+                 vector<Drul_array<Offset> > &buildings,
+                 PangoMatrix trans, SCM expr)
 {
   return internal_make_path_boxes (boxes, buildings, trans, scm_cons (scm_car (expr), get_path_list (scm_cdr (expr))), false);
 }
 
 void
-make_polygon_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr)
+make_polygon_boxes (vector<Box> &boxes,
+                    vector<Drul_array<Offset> > &buildings,
+                    PangoMatrix trans, SCM expr)
 {
   SCM coords = get_number_list (scm_car (expr));
   expr = scm_cdr (expr);
@@ -685,14 +654,17 @@ make_polygon_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
       first = false;
     }
   l = scm_cons (ly_symbol2scm ("closepath"), l);
-  internal_make_path_boxes (boxes, buildings, trans, scm_cons (blot_diameter, scm_reverse_x (l, SCM_EOL)), true);
+  internal_make_path_boxes (boxes, buildings, trans,
+                            scm_cons (blot_diameter, scm_reverse_x (l, SCM_EOL)), true);
 }
 
 void
-make_named_glyph_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr)
+make_named_glyph_boxes (vector<Box> &boxes,
+                        vector<Drul_array<Offset> > &buildings,
+                        PangoMatrix trans, SCM expr)
 {
   SCM fm_scm = scm_car (expr);
-  Font_metric *fm = unsmob_metrics (fm_scm);
+  Font_metric *fm = unsmob<Font_metric> (fm_scm);
   expr = scm_cdr (expr);
   SCM glyph = scm_car (expr);
   string glyph_s = ly_scm2string (glyph);
@@ -707,7 +679,8 @@ make_named_glyph_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildin
   // Bbox is the best approximation of the width based on how it would be
   // calculated in open-type-font.cc if it were based on real extents
   Box bbox = open_fm->get_unscaled_indexed_char_dimensions (gidx);
-  bbox.scale (dynamic_cast<Modified_font_metric *>(fm)->get_magnification () * open_fm->design_size () / open_fm->get_units_per_EM ());
+  bbox.scale (dynamic_cast<Modified_font_metric *> (fm)->get_magnification ()
+              * open_fm->design_size () / open_fm->get_units_per_EM ());
   // Real bbox is the real bbox of the object
   Box real_bbox = open_fm->get_glyph_outline_bbox (gidx);
 
@@ -722,16 +695,21 @@ make_named_glyph_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildin
        s = scm_cdr (s))
     {
       scm_to_int (scm_length (scm_car (s))) == 4
-      ? make_draw_line_boxes (boxes, buildings, trans, scm_cons (scm_from_double (0), scm_car (s)), false)
-      : make_draw_bezier_boxes (boxes, buildings, trans, scm_cons (scm_from_double (0), scm_car (s)));
+      ? make_draw_line_boxes (boxes, buildings, trans,
+                              scm_cons (scm_from_double (0), scm_car (s)),
+                              false)
+      : make_draw_bezier_boxes (boxes, buildings, trans,
+                                scm_cons (scm_from_double (0), scm_car (s)));
     }
 }
 
 void
-make_glyph_string_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr)
+make_glyph_string_boxes (vector<Box> &boxes,
+                         vector<Drul_array<Offset> > &buildings,
+                         PangoMatrix trans, SCM expr)
 {
   SCM fm_scm = scm_car (expr);
-  Font_metric *fm = unsmob_metrics (fm_scm);
+  Font_metric *fm = unsmob<Font_metric> (fm_scm);
   expr = scm_cdr (expr);
   expr = scm_cdr (expr); // font-name
   expr = scm_cdr (expr); // size
@@ -798,10 +776,13 @@ make_glyph_string_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildi
 
           Real scale_factor = max (xlen, ylen);
           // the three operations below move the stencil from its original coordinates to current coordinates
-          pango_matrix_translate (&transcopy, kerned_bbox[X_AXIS][LEFT], kerned_bbox[Y_AXIS][DOWN] - real_bbox[Y_AXIS][DOWN]);
-          pango_matrix_translate (&transcopy, real_bbox[X_AXIS][LEFT], real_bbox[Y_AXIS][DOWN]);
+          pango_matrix_translate (&transcopy, kerned_bbox[X_AXIS][LEFT],
+                                  kerned_bbox[Y_AXIS][DOWN] - real_bbox[Y_AXIS][DOWN]);
+          pango_matrix_translate (&transcopy, real_bbox[X_AXIS][LEFT],
+                                  real_bbox[Y_AXIS][DOWN]);
           pango_matrix_scale (&transcopy, scale_factor, scale_factor);
-          pango_matrix_translate (&transcopy, -bbox[X_AXIS][LEFT], -bbox[Y_AXIS][DOWN]);
+          pango_matrix_translate (&transcopy, -bbox[X_AXIS][LEFT],
+                                  -bbox[Y_AXIS][DOWN]);
         }
       //////////////////////
       for (SCM s = outline;
@@ -809,8 +790,11 @@ make_glyph_string_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildi
            s = scm_cdr (s))
         {
           scm_to_int (scm_length (scm_car (s))) == 4
-          ? make_draw_line_boxes (boxes, buildings, transcopy, scm_cons (scm_from_double (0), scm_car (s)), false)
-          : make_draw_bezier_boxes (boxes, buildings, transcopy, scm_cons (scm_from_double (0), scm_car (s)));
+          ? make_draw_line_boxes (boxes, buildings, transcopy,
+                                  scm_cons (scm_from_double (0), scm_car (s)),
+                                  false)
+          : make_draw_bezier_boxes (boxes, buildings, transcopy,
+                                    scm_cons (scm_from_double (0), scm_car (s)));
         }
     }
 }
@@ -821,13 +805,15 @@ make_glyph_string_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildi
 */
 
 void
-stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings, PangoMatrix trans, SCM expr)
+stencil_dispatcher (vector<Box> &boxes,
+                    vector<Drul_array<Offset> > &buildings,
+                    PangoMatrix trans, SCM expr)
 {
   if (not scm_is_pair (expr))
     return;
-  if (scm_car (expr) == ly_symbol2scm ("draw-line"))
+  if (scm_is_eq (scm_car (expr), ly_symbol2scm ("draw-line")))
     make_draw_line_boxes (boxes, buildings, trans, scm_cdr (expr), true);
-  else if (scm_car (expr) == ly_symbol2scm ("dashed-line"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("dashed-line")))
     {
       expr = scm_cdr (expr);
       SCM th = scm_car (expr);
@@ -837,9 +823,11 @@ stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
       SCM x1 = scm_car (expr);
       expr = scm_cdr (expr);
       SCM x2 = scm_car (expr);
-      make_draw_line_boxes (boxes, buildings, trans, scm_list_5 (th, scm_from_double (0.0), scm_from_double (0.0), x1, x2), true);
+      make_draw_line_boxes (boxes, buildings, trans,
+                            scm_list_5 (th, scm_from_double (0.0),
+                                        scm_from_double (0.0), x1, x2), true);
     }
-  else if (scm_car (expr) == ly_symbol2scm ("circle"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("circle")))
     {
       expr = scm_cdr (expr);
       SCM rad = scm_car (expr);
@@ -855,7 +843,7 @@ stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
                                               SCM_BOOL_T,
                                               SCM_UNDEFINED));
     }
-  else if (scm_car (expr) == ly_symbol2scm ("ellipse"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("ellipse")))
     {
       expr = scm_cdr (expr);
       SCM x_rad = scm_car (expr);
@@ -873,17 +861,17 @@ stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
                                               SCM_BOOL_T,
                                               SCM_UNDEFINED));
     }
-  else if (scm_car (expr) == ly_symbol2scm ("partial-ellipse"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("partial-ellipse")))
     make_partial_ellipse_boxes (boxes, buildings, trans, scm_cdr (expr));
-  else if (scm_car (expr) == ly_symbol2scm ("round-filled-box"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("round-filled-box")))
     make_round_filled_box_boxes (boxes, trans, scm_cdr (expr));
-  else if (scm_car (expr) == ly_symbol2scm ("named-glyph"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("named-glyph")))
     make_named_glyph_boxes (boxes, buildings, trans, scm_cdr (expr));
-  else if (scm_car (expr) == ly_symbol2scm ("polygon"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("polygon")))
     make_polygon_boxes (boxes, buildings, trans, scm_cdr (expr));
-  else if (scm_car (expr) == ly_symbol2scm ("path"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("path")))
     make_path_boxes (boxes, buildings, trans, scm_cdr (expr));
-  else if (scm_car (expr) == ly_symbol2scm ("glyph-string"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("glyph-string")))
     make_glyph_string_boxes (boxes, buildings, trans, scm_cdr (expr));
   else
     {
@@ -906,37 +894,37 @@ stencil_dispatcher (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings,
 vector<Transform_matrix_and_expression>
 stencil_traverser (PangoMatrix trans, SCM expr)
 {
-  if (scm_is_null (expr))
-    return vector<Transform_matrix_and_expression> ();
-  else if (expr == ly_string2scm (""))
+  if (scm_is_null (expr)
+      || (scm_is_string (expr) && scm_is_true (scm_string_null_p (expr))))
     return vector<Transform_matrix_and_expression> ();
-  else if (scm_car (expr) == ly_symbol2scm ("combine-stencil"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("combine-stencil")))
     {
       vector<Transform_matrix_and_expression> out;
       for (SCM s = scm_cdr (expr); scm_is_pair (s); s = scm_cdr (s))
         {
-          vector<Transform_matrix_and_expression> res = stencil_traverser (trans, scm_car (s));
+          vector<Transform_matrix_and_expression> res =
+            stencil_traverser (trans, scm_car (s));
           out.insert (out.end (), res.begin (), res.end ());
         }
       return out;
     }
-  else if (scm_car (expr) == ly_symbol2scm ("footnote"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("footnote")))
     return vector<Transform_matrix_and_expression> ();
-  else if (scm_car (expr) == ly_symbol2scm ("translate-stencil"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("translate-stencil")))
     {
       Real x = robust_scm2double (scm_caadr (expr), 0.0);
       Real y = robust_scm2double (scm_cdadr (expr), 0.0);
       pango_matrix_translate (&trans, x, y);
       return stencil_traverser (trans, scm_caddr (expr));
     }
-  else if (scm_car (expr) == ly_symbol2scm ("scale-stencil"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("scale-stencil")))
     {
       Real x = robust_scm2double (scm_caadr (expr), 0.0);
       Real y = robust_scm2double (scm_cadadr (expr), 0.0);
       pango_matrix_scale (&trans, x, y);
       return stencil_traverser (trans, scm_caddr (expr));
     }
-  else if (scm_car (expr) == ly_symbol2scm ("rotate-stencil"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("rotate-stencil")))
     {
       Real ang = robust_scm2double (scm_caadr (expr), 0.0);
       Real x = robust_scm2double (scm_car (scm_cadadr (expr)), 0.0);
@@ -946,14 +934,19 @@ stencil_traverser (PangoMatrix trans, SCM expr)
       pango_matrix_translate (&trans, -x, -y);
       return stencil_traverser (trans, scm_caddr (expr));
     }
-  else if (scm_car (expr) == ly_symbol2scm ("delay-stencil-evaluation"))
-    return stencil_traverser (trans, scm_force (scm_cadr (expr)));
-  else if (scm_car (expr) == ly_symbol2scm ("grob-cause"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("delay-stencil-evaluation")))
+    // should not use the place-holder text, but no need for the warning below
+    return vector<Transform_matrix_and_expression> ();
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("grob-cause")))
     return stencil_traverser (trans, scm_caddr (expr));
-  else if (scm_car (expr) == ly_symbol2scm ("color"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("color")))
     return stencil_traverser (trans, scm_caddr (expr));
-  else if (scm_car (expr) == ly_symbol2scm ("id"))
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("transparent-stencil")))
+    return stencil_traverser (trans, scm_cadr (expr));
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("output-attributes")))
     return stencil_traverser (trans, scm_caddr (expr));
+  else if (scm_is_eq (scm_car (expr), ly_symbol2scm ("with-outline")))
+    return stencil_traverser (trans, scm_cadr (expr));
   else
     {
       vector<Transform_matrix_and_expression> out;
@@ -992,19 +985,19 @@ MAKE_SCHEME_CALLBACK (Grob, pure_simple_vertical_skylines_from_extents, 3);
 SCM
 Grob::pure_simple_vertical_skylines_from_extents (SCM smob, SCM begscm, SCM endscm)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   int beg = robust_scm2int (begscm, 0);
   int end = robust_scm2int (endscm, INT_MAX);
-  // We cannot measure the width of a spanner before line breaking,
-  // so we assume that the width is infinite.
-  return maybe_pure_internal_simple_skylines_from_extents (me, X_AXIS, true, beg, end, dynamic_cast<Spanner *> (me), false);
+  // We cannot measure the widths before line breaking,
+  // so we assume that the width is infinite: pass ignore_x=true
+  return maybe_pure_internal_simple_skylines_from_extents (me, X_AXIS, true, beg, end, true, false);
 }
 
 MAKE_SCHEME_CALLBACK (Grob, simple_vertical_skylines_from_extents, 1);
 SCM
 Grob::simple_vertical_skylines_from_extents (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   return maybe_pure_internal_simple_skylines_from_extents (me, X_AXIS, false, 0, 0, false, false);
 }
 
@@ -1012,7 +1005,7 @@ MAKE_SCHEME_CALLBACK (Grob, pure_simple_horizontal_skylines_from_extents, 3);
 SCM
 Grob::pure_simple_horizontal_skylines_from_extents (SCM smob, SCM begscm, SCM endscm)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   int beg = robust_scm2int (begscm, 0);
   int end = robust_scm2int (endscm, INT_MAX);
   // If the grob is cross staff, we cannot measure its Y-extent before
@@ -1025,7 +1018,7 @@ MAKE_SCHEME_CALLBACK (Grob, simple_horizontal_skylines_from_extents, 1);
 SCM
 Grob::simple_horizontal_skylines_from_extents (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   // See comment in function above.
   return maybe_pure_internal_simple_skylines_from_extents (me, Y_AXIS, false, 0, 0, false, to_boolean (me->get_property ("cross-staff")));
 }
@@ -1033,7 +1026,7 @@ Grob::simple_horizontal_skylines_from_extents (SCM smob)
 SCM
 Stencil::skylines_from_stencil (SCM sten, Real pad, Axis a)
 {
-  Stencil *s = unsmob_stencil (sten);
+  Stencil *s = unsmob<Stencil> (sten);
   if (!s)
     return Skyline_pair ().smobbed_copy ();
 
@@ -1055,7 +1048,6 @@ Stencil::skylines_from_stencil (SCM sten, Real pad, Axis a)
   for (DOWN_and_UP (d))
     out[d] = out[d].padded (pad);
 
-  out.deholify ();
   return out.smobbed_copy ();
 }
 
@@ -1063,7 +1055,7 @@ MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_stencil, 1);
 SCM
 Grob::vertical_skylines_from_stencil (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
 
   Real pad = robust_scm2double (me->get_property ("skyline-horizontal-padding"), 0.0);
   SCM out = Stencil::skylines_from_stencil (me->get_property ("stencil"), pad, X_AXIS);
@@ -1075,7 +1067,7 @@ MAKE_SCHEME_CALLBACK (Grob, horizontal_skylines_from_stencil, 1);
 SCM
 Grob::horizontal_skylines_from_stencil (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
 
   Real pad = robust_scm2double (me->get_property ("skyline-vertical-padding"), 0.0);
   SCM out = Stencil::skylines_from_stencil (me->get_property ("stencil"), pad, Y_AXIS);
@@ -1103,7 +1095,7 @@ Grob::internal_skylines_from_element_stencils (Grob *me, Axis a, bool pure, int
   Skyline_pair res;
   for (vsize i = 0; i < elts.size (); i++)
     {
-      Skyline_pair *skyp = Skyline_pair::unsmob (elts[i]->get_maybe_pure_property (a == X_AXIS ? "vertical-skylines" : "horizontal-skylines", pure, beg, end));
+      Skyline_pair *skyp = unsmob<Skyline_pair> (elts[i]->get_maybe_pure_property (a == X_AXIS ? "vertical-skylines" : "horizontal-skylines", pure, beg, end));
       if (skyp)
         {
           /*
@@ -1137,7 +1129,7 @@ MAKE_SCHEME_CALLBACK (Grob, vertical_skylines_from_element_stencils, 1);
 SCM
 Grob::vertical_skylines_from_element_stencils (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   return internal_skylines_from_element_stencils (me, X_AXIS, false, 0, INT_MAX);
 }
 
@@ -1145,7 +1137,7 @@ MAKE_SCHEME_CALLBACK (Grob, horizontal_skylines_from_element_stencils, 1);
 SCM
 Grob::horizontal_skylines_from_element_stencils (SCM smob)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   return internal_skylines_from_element_stencils (me, Y_AXIS, false, 0, INT_MAX);
 }
 
@@ -1153,7 +1145,7 @@ MAKE_SCHEME_CALLBACK (Grob, pure_vertical_skylines_from_element_stencils, 3);
 SCM
 Grob::pure_vertical_skylines_from_element_stencils (SCM smob, SCM beg_scm, SCM end_scm)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   int beg = robust_scm2int (beg_scm, 0);
   int end = robust_scm2int (end_scm, 0);
   return internal_skylines_from_element_stencils (me, X_AXIS, true, beg, end);
@@ -1163,7 +1155,7 @@ MAKE_SCHEME_CALLBACK (Grob, pure_horizontal_skylines_from_element_stencils, 3);
 SCM
 Grob::pure_horizontal_skylines_from_element_stencils (SCM smob, SCM beg_scm, SCM end_scm)
 {
-  Grob *me = unsmob_grob (smob);
+  Grob *me = unsmob<Grob> (smob);
   int beg = robust_scm2int (beg_scm, 0);
   int end = robust_scm2int (end_scm, 0);
   return internal_skylines_from_element_stencils (me, Y_AXIS, true, beg, end);