Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions docs/font-metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,40 @@ Each font can optionally provide a metadata file containing information that can

All positions and widths are specified in ems.

## metrics

This section contains font-wide measurements and adjustments. The
`elafronBounds` object gives the horizontal outline bounds of the elafron
component in composite glyphs.

```js
{
"metrics": {
"ascent": 0.8,
"descent": 0.2,
"winAscent": 1.4,
"winDescent": 0.466,
"oligonMidpoint": 0.307,
"elafronBounds": {
"runningElafron": {
"left": 0.59,
"right": 1.696
},
"petastiRunningElafron": {
"left": 0.425,
"right": 1.431
}
}
},
...
}
```

These bounds can be used to terminate a melisma at the component's edge
without assuming that it matches the stand-alone glyph. Given the composite
glyph's advance width, the signed offset needed to center lyrics beneath its
elafron is `left + right - advanceWidth`.

## glyphsWithAnchors

This section contains the anchor points for all glyphs that contain anchors. If mark-to-base positioning is not available, marks can be positioned using the data in this section.
Expand Down
12 changes: 11 additions & 1 deletion fonts/neanes.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
"descent": 0.2,
"winAscent": 1.4,
"winDescent": 0.466,
"oligonMidpoint": 0.307
"oligonMidpoint": 0.307,
"elafronBounds": {
"runningElafron": {
"left": 0.59,
"right": 1.696
},
"petastiRunningElafron": {
"left": 0.425,
"right": 1.431
}
}
},
"glyphsWithAnchors": {
"ison": {
Expand Down
12 changes: 11 additions & 1 deletion fonts/neanesengraving.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
"descent": 0.2,
"winAscent": 1.4,
"winDescent": 0.466,
"oligonMidpoint": 0.307
"oligonMidpoint": 0.307,
"elafronBounds": {
"runningElafron": {
"left": 0.542,
"right": 1.648
},
"petastiRunningElafron": {
"left": 0.502,
"right": 1.508
}
}
},
"glyphsWithAnchors": {
"ison": {
Expand Down
12 changes: 11 additions & 1 deletion fonts/neanesrtl.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
"descent": 0.2,
"winAscent": 1.4,
"winDescent": 0.466,
"oligonMidpoint": 0.307
"oligonMidpoint": 0.307,
"elafronBounds": {
"runningElafron": {
"left": 0.08,
"right": 1.185
},
"petastiRunningElafron": {
"left": 0.085,
"right": 1.091
}
}
},
"glyphsWithAnchors": {
"ison": {
Expand Down
12 changes: 11 additions & 1 deletion fonts/neanesrtlengraving.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
"descent": 0.2,
"winAscent": 1.4,
"winDescent": 0.466,
"oligonMidpoint": 0.307
"oligonMidpoint": 0.307,
"elafronBounds": {
"runningElafron": {
"left": -0.002,
"right": 1.104
},
"petastiRunningElafron": {
"left": 0.019,
"right": 1.024
}
}
},
"glyphsWithAnchors": {
"ison": {
Expand Down
12 changes: 11 additions & 1 deletion fonts/neanesstathisseries.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
"descent": 0.2,
"winAscent": 1.4,
"winDescent": 0.466,
"oligonMidpoint": 0.309
"oligonMidpoint": 0.309,
"elafronBounds": {
"runningElafron": {
"left": 0.72,
"right": 1.772
},
"petastiRunningElafron": {
"left": 0.389,
"right": 1.515
}
}
},
"glyphsWithAnchors": {
"ison": {
Expand Down
12 changes: 11 additions & 1 deletion fonts/neanesstathisseriesengraving.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
"descent": 0.2,
"winAscent": 1.4,
"winDescent": 0.466,
"oligonMidpoint": 0.309
"oligonMidpoint": 0.309,
"elafronBounds": {
"runningElafron": {
"left": 0.72,
"right": 1.772
},
"petastiRunningElafron": {
"left": 0.721,
"right": 1.847
}
}
},
"glyphsWithAnchors": {
"ison": {
Expand Down
45 changes: 45 additions & 0 deletions scripts/generate-font-metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ def contour_bbox(contour):
return xmin, ymin, xmax, ymax


def find_widest_contour_bbox(glyph):
bboxes = [bbox for contour in glyph.foreground if (bbox := contour_bbox(contour))]

if not bboxes:
return None

return max(bboxes, key=lambda bbox: bbox[2] - bbox[0])


def find_lowest_contour_bbox(glyph):
bboxes = [bbox for contour in glyph.foreground if (bbox := contour_bbox(contour))]

if not bboxes:
return None

return min(bboxes, key=lambda bbox: bbox[1])


def create_temp_glyph_from_contours(font, source_glyph, contours, name):
temp_glyph = font.createChar(-1, name)
temp_glyph.clear()
Expand Down Expand Up @@ -355,6 +373,7 @@ def asdict(self):
"winAscent": round(self.font.os2_winascent / self.font.em, 3),
"winDescent": round(self.font.os2_windescent / self.font.em, 3),
"oligonMidpoint": round(self.font.oligon_midpoint / self.font.em, 3),
"elafronBounds": self.elafron_bounds(),
}

anchors = self.anchors()
Expand Down Expand Up @@ -396,6 +415,32 @@ def asdict(self):

return d

def elafron_bounds(self):
# In runningElafron the wider of the two adjacent contours is the
# elafron. In petastiRunningElafron the elafron is the contour below
# the petasti. Derive the component bounds from those outlines instead
# of assuming they match the stand-alone elafron.
contour_bboxes = {
"runningElafron": find_widest_contour_bbox(self.font["runningElafron"]),
"petastiRunningElafron": find_lowest_contour_bbox(
self.font["petastiRunningElafron"]
),
}

bounds = {}

for glyph_name, bbox in contour_bboxes.items():
if bbox is None:
raise ValueError(f"Cannot locate the elafron in {glyph_name}")

elafron_left, _, elafron_right, _ = bbox
bounds[glyph_name] = {
"left": round(elafron_left / self.font.em, 3),
"right": round(elafron_right / self.font.em, 3),
}

return bounds

def anchors(self):
all_anchors = {}

Expand Down