Skip to content

Commit

Permalink
Merge pull request #424 from googlefonts/zero-width-colr-to-svg
Browse files Browse the repository at this point in the history
fix maximum_color'ing 0-width glyphs
  • Loading branch information
anthrotype authored Aug 18, 2022
2 parents d65a627 + de3147e commit bf36fa0
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 12 deletions.
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

0 comments on commit bf36fa0

Please sign in to comment.