Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix maximum_color'ing 0-width glyphs #424

Merged
merged 7 commits into from
Aug 18, 2022
8 changes: 0 additions & 8 deletions src/nanoemoji/colr_to_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,6 @@ def glyph_region(ttfont: ttLib.TTFont, glyph_name: str) -> Rect:

map_font_space_to_viewbox handles font +y goes up => svg +y goes down."""
width = ttfont["hmtx"][glyph_name][0]
if width == 0:
width = ttfont["glyf"][glyph_name].xMax
return Rect(
0,
-ttfont["OS/2"].sTypoAscender,
Expand All @@ -325,15 +323,9 @@ def glyph_region(ttfont: ttLib.TTFont, glyph_name: str) -> Rect:
def _view_box_and_transform(
ttfont: ttLib.TTFont, view_box_callback: ViewboxCallback, glyph_name: str
) -> Tuple[Rect, Affine2D]:

view_box = view_box_callback(glyph_name)
assert view_box.w > 0, f"0-width viewBox for {glyph_name}?!"

region = glyph_region(ttfont, glyph_name)
assert region.w > 0, f"0-width region for {glyph_name}?!"

font_to_vbox = map_font_space_to_viewbox(view_box, region)

return (view_box, font_to_vbox)


Expand Down
4 changes: 1 addition & 3 deletions src/nanoemoji/generate_svgs_from_colr.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@

def _view_box(font: ttLib.TTFont, glyph_name: str) -> Rect:
# we want a viewbox that results in no scaling when translating from font-space
region = glyph_region(font, glyph_name)
assert region.w > 0, f"0-width region for {glyph_name}"
return region
return glyph_region(font, glyph_name)


def main(argv):
Expand Down
53 changes: 53 additions & 0 deletions tests/maximum_color_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import copy
from fontTools import ttLib
from nanoemoji.keep_glyph_names import keep_glyph_names
from picosvg.svg import SVG
from pathlib import Path
import pytest
import sys
Expand Down Expand Up @@ -109,3 +110,55 @@ def test_keep_glyph_names(keep_names):
assert all(
not gn.startswith("duck_") for gn in maximum_font.getGlyphOrder()
), maximum_font.getGlyphOrder()


def test_zero_advance_width_colrv1_to_svg():
tmp_dir = run_nanoemoji(
(
"--color_format",
"glyf_colr_1",
# use proportional widths, based on viewBox.w
"--width=0",
# don't clip to viewBox else zero-width glyph disappears
"--noclip_to_viewbox",
locate_test_file("emoji_u42.svg"),
# this one has viewBox="0 0 0 1200", i.e. zero width, like
# combining marks usually are (e.g. 'acutecomb')
locate_test_file("u0301.svg"),
)
)

initial_font_file = tmp_dir / "Font.ttf"
assert initial_font_file.is_file()

initial_font = ttLib.TTFont(initial_font_file)
# sanity check widths are proportional and we have 2 colr glyphs
assert initial_font["hmtx"]["B"] == (1200, 0)
assert initial_font["hmtx"]["acutecomb"] == (0, 0)
assert initial_font["COLR"].table.BaseGlyphList.BaseGlyphCount == 2

maxmium_font_file = _maximize_color(initial_font_file, ())
maximum_font = ttLib.TTFont(maxmium_font_file)

assert "COLR" in maximum_font
assert maximum_font["COLR"].table.BaseGlyphList.BaseGlyphCount == 2
assert "SVG " in maximum_font
assert len(maximum_font["SVG "].docList) == 2

# check that 'acutecomb' still has 0 advance width
assert initial_font["hmtx"]["acutecomb"] == (0, 0)
# it has not been cropped away (has a non-empty bounding box)
doc = maximum_font["SVG "].docList[1]
assert doc.startGlyphID == doc.endGlyphID == maximum_font.getGlyphID("acutecomb")
svg = SVG.fromstring(doc.data)
shapes = list(svg.shapes())
assert len(shapes) == 1
bbox = shapes[0].bounding_box()
assert bbox.w > 0
assert bbox.h > 0
# its bbox matches the respective COLR ClipBox dimensions (quantized to 10)
clipBox = maximum_font["COLR"].table.ClipList.clips["acutecomb"]
assert abs(bbox.w - (clipBox.xMax - clipBox.xMin)) <= 10
assert abs(bbox.h - (clipBox.yMax - clipBox.yMin)) <= 10
# the SVG shape's horizontal positioning also matches the respective COLR glyph
assert abs(bbox.x - clipBox.xMin) <= 10
2 changes: 1 addition & 1 deletion tests/nanoemoji_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ def test_glyph_with_zero_advance_width(color_format, tmp_path):
svg = font["SVG "]
assert len(svg.docList) == 1
gid = font.getGlyphID(gname)
assert svg.docList[0][1:] == [gid, gid] # [start, end]
assert svg.docList[0][1:] == (gid, gid) # (start, end)
if "CBDT" in font:
cbdt = font["CBDT"]
assert len(cbdt.strikeData) == 1
Expand Down