Skip to content

Commit

Permalink
Merge pull request #417 from googlefonts/part_wip
Browse files Browse the repository at this point in the history
Generate part files for each svg, merge them, but don't yet use the result
  • Loading branch information
rsheeter authored Jun 11, 2022
2 parents e2f7c92 + f662ad5 commit d65a627
Show file tree
Hide file tree
Showing 17 changed files with 633 additions and 127 deletions.
6 changes: 3 additions & 3 deletions src/nanoemoji/color_glyph.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
import pathops


def _scale_viewbox_to_font_metrics(
def scale_viewbox_to_font_metrics(
view_box: Rect, ascender: int, descender: int, width: int
):
assert descender <= 0
Expand All @@ -71,7 +71,7 @@ def map_viewbox_to_font_space(
) -> Affine2D:
return Affine2D.compose_ltr(
[
_scale_viewbox_to_font_metrics(view_box, ascender, descender, width),
scale_viewbox_to_font_metrics(view_box, ascender, descender, width),
# flip y axis and shift so things are in the right place
Affine2D(1, 0, 0, -1, 0, ascender),
user_transform,
Expand All @@ -85,7 +85,7 @@ def map_viewbox_to_otsvg_space(
) -> Affine2D:
return Affine2D.compose_ltr(
[
_scale_viewbox_to_font_metrics(view_box, ascender, descender, width),
scale_viewbox_to_font_metrics(view_box, ascender, descender, width),
# shift things in the [+x,-y] quadrant where OT-SVG expects them
Affine2D(1, 0, 0, 1, 0, -ascender),
user_transform,
Expand Down
82 changes: 75 additions & 7 deletions src/nanoemoji/maximum_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
class WriteFontInputs(NamedTuple):
glyphmap_file: Path
config_file: Path
part_file: Path

@property
def table_tag(self) -> str:
Expand All @@ -88,7 +89,11 @@ def color_format(self) -> str:
@classmethod
def for_tag(cls, table_tag: str) -> "WriteFontInputs":
basename = table_tag.strip()
return cls(Path(basename + ".glyphmap"), Path(basename + ".toml"))
return cls(
Path(basename + ".glyphmap"),
Path(basename + ".toml"),
master_part_file_dest(),
)


def _vector_color_table(font: ttLib.TTFont) -> str:
Expand Down Expand Up @@ -121,6 +126,14 @@ def picosvg_dest(input_svg: Path) -> Path:
return picosvg_dir() / input_svg.name


def part_file_dest(picosvg_file: Path) -> Path:
return picosvg_file.with_suffix(".parts.json")


def master_part_file_dest() -> Path:
return Path("parts-merged.json")


def bitmap_dir() -> Path:
return build_dir() / "bitmap"

Expand Down Expand Up @@ -163,7 +176,7 @@ def _write_preamble(nw: NinjaWriter):
module_rule(
nw,
"write_font",
f"--glyphmap_file $glyphmap_file --config_file $config_file --output_file $out",
f"--config_file $config_file --glyphmap_file $glyphmap_file --part_file $part_file --output_file $out",
)
nw.newline()

Expand All @@ -173,6 +186,22 @@ def _write_preamble(nw: NinjaWriter):
)
nw.newline()

module_rule(
nw,
"write_part_file",
f"--reuse_tolerance $reuse_tolerance --wh $wh --output_file $out $in",
)
nw.newline()

module_rule(
nw,
"write_combined_part_files",
f"--output_file $out @$out.rsp",
rspfile="$out.rsp",
rspfile_content="$in",
)
nw.newline()

# set height only, let width scale proportionally
res = config.load().bitmap_resolution
nw.rule(
Expand Down Expand Up @@ -237,6 +266,30 @@ def _picosvgs(nw: NinjaWriter, svg_files: List[Path]) -> List[Path]:
return picosvgs


def _part_file(
nw: NinjaWriter, font_config: config.FontConfig, picosvg_files: List[Path]
) -> Path:
part_files = [part_file_dest(p) for p in picosvg_files]
for picosvg_file, part_file in zip(picosvg_files, part_files):
nw.build(
part_file,
"write_part_file",
picosvg_file,
variables={
"reuse_tolerance": font_config.reuse_tolerance,
"wh": font_config.ascender - font_config.descender,
},
)

nw.build(
master_part_file_dest(),
"write_combined_part_files",
sorted(part_files),
)

return master_part_file_dest()


def _generate_additional_color_table(
nw: NinjaWriter,
input_font: Path,
Expand Down Expand Up @@ -283,7 +336,10 @@ def _generate_additional_color_table(


def _generate_svg_from_colr(
nw: NinjaWriter, input_font: Path, font: ttLib.TTFont
nw: NinjaWriter,
font_config: config.FontConfig,
input_font: Path,
font: ttLib.TTFont,
) -> Tuple[Path, List[Path]]:
# generate svgs
svg_files = [
Expand All @@ -294,14 +350,19 @@ def _generate_svg_from_colr(

# create and merge an SVG table
picosvgs = _picosvgs(nw, svg_files)
part_file = _part_file(nw, font_config, picosvgs)

output_file = _generate_additional_color_table(
nw, input_font, picosvgs + [input_font], "SVG ", input_font
)
return output_file, picosvgs


def _generate_colr_from_svg(
nw: NinjaWriter, input_font: Path, font: ttLib.TTFont
nw: NinjaWriter,
font_config: config.FontConfig,
input_font: Path,
font: ttLib.TTFont,
) -> Tuple[Path, List[Path]]:
# extract the svgs
svg_files = [
Expand All @@ -312,6 +373,8 @@ def _generate_colr_from_svg(

# create and merge a COLR table
picosvgs = _picosvgs(nw, svg_files)
part_file = _part_file(nw, font_config, picosvgs)

output_file = _generate_additional_color_table(
nw, input_font, picosvgs + [input_font], "COLR", input_font
)
Expand Down Expand Up @@ -371,7 +434,8 @@ def _run(argv):
input_file = Path(argv[1]).resolve() # we need a non-relative path
assert input_file.is_file()
font = ttLib.TTFont(input_file)
final_output = Path(config.load().output_file)
font_config = config.load()
final_output = Path(font_config.output_file)
assert (
input_file.resolve() != (build_dir() / final_output).resolve()
), "In == Out is bad"
Expand All @@ -391,9 +455,13 @@ def _run(argv):

# generate the missing vector table
if color_table == "COLR":
wip_file, picosvg_files = _generate_svg_from_colr(nw, wip_file, font)
wip_file, picosvg_files = _generate_svg_from_colr(
nw, font_config, wip_file, font
)
else:
wip_file, picosvg_files = _generate_colr_from_svg(nw, wip_file, font)
wip_file, picosvg_files = _generate_colr_from_svg(
nw, font_config, wip_file, font
)

if FLAGS.bitmaps:
wip_file = _generate_cbdt(nw, input_file, font, wip_file, picosvg_files)
Expand Down
64 changes: 48 additions & 16 deletions src/nanoemoji/nanoemoji.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,19 @@ def write_preamble(nw):
)
nw.newline()

module_rule(
nw,
"write_combined_part_files",
f"--output_file $out @$out.rsp",
rspfile="$out.rsp",
rspfile_content="$in",
)
nw.newline()

module_rule(
nw,
"write_font",
f"--config_file $config_file --fea_file $fea_file --glyphmap_file $glyphmap_file $in",
f"--config_file $config_file --fea_file $fea_file --glyphmap_file $glyphmap_file --part_file $part_file $in",
)

module_rule(
Expand Down Expand Up @@ -252,7 +261,7 @@ def write_preamble(nw):
module_rule(
nw,
"write_part_file",
f"--reuse_tolerance $reuse_tolerance --output_file $out $in",
f"--reuse_tolerance $reuse_tolerance --wh $wh --output_file $out $in",
)
nw.newline()

Expand Down Expand Up @@ -344,31 +353,45 @@ def diff_png_dest(input_svg: Path) -> Path:
return _dest_for_src(diff_png_dest, diff_bitmap_dir(), input_svg, ".png")


def master_part_file_dest() -> Path:
return Path("parts-merged.json")


def write_picosvg_builds(
picosvg_builds: Set[Path],
nw: NinjaWriter,
clipped: bool,
reuse_tolerance: float,
font_config: FontConfig,
master: MasterConfig,
):
) -> Tuple[Set[Path], Set[Path]]:
rule_name = "picosvg_unclipped"
if clipped:
if font_config.clip_to_viewbox:
rule_name = "picosvg_clipped"

picosvgs = set()
part_files = set()
for svg_file in master.sources:
svg_file = abspath(svg_file)
dest = picosvg_dest(clipped, svg_file)
dest = picosvg_dest(font_config.clip_to_viewbox, svg_file)
if svg_file in picosvg_builds:
continue
picosvg_builds.add(svg_file)
nw.build(dest, rule_name, rel_build(svg_file))

part_dest = part_file_dest(dest)
nw.build(
part_file_dest(dest),
part_dest,
"write_part_file",
dest,
variables={"reuse_tolerance": reuse_tolerance},
variables={
"reuse_tolerance": font_config.reuse_tolerance,
"wh": font_config.ascender - font_config.descender,
},
)

picosvgs.add(dest)
part_files.add(part_dest)
return (picosvgs, part_files)


def write_bitmap_builds(
bitmap_builds: Set[Path],
Expand Down Expand Up @@ -525,6 +548,7 @@ def _variables_for_font_build(
"config_file": rel_build(config_file),
"fea_file": rel_build(_fea_file(font_config)),
"glyphmap_file": rel_build(_glyphmap_file(font_config, master)),
"part_file": master_part_file_dest(),
}


Expand Down Expand Up @@ -637,20 +661,28 @@ def _run(argv):
for master in font_config.masters:
write_glyphmap_build(nw, font_config, master)

picosvg_builds = set()
picosvg_builds = set() # svgs for which we already made a picosvg
part_files = set()
for font_config in font_configs:
for master in font_config.masters:
if font_config.has_picosvgs:
write_picosvg_builds(
_, parts = write_picosvg_builds(
picosvg_builds,
nw,
font_config.clip_to_viewbox,
font_config.reuse_tolerance,
font_config,
master,
)
part_files |= parts
nw.newline()

bitmap_builds = set()
# Write a combined part file (potentially empty)
nw.build(
master_part_file_dest(),
"write_combined_part_files",
sorted(part_files),
)

bitmap_builds = set() # svgs for which we already made a bitmap
for font_config in font_configs:
if font_config.has_bitmaps:
assert not font_config.is_vf
Expand All @@ -663,8 +695,8 @@ def _run(argv):
)
nw.newline()

zopflipng_builds = set()
pngquant_builds = set()
zopflipng_builds = set() # svgs for which we already made a zopflipng
pngquant_builds = set() # svgs for which we already made a pngquant
for font_config in font_configs:
if not font_config.has_bitmaps or not (
font_config.use_zopflipng or font_config.use_pngquant
Expand Down
Loading

0 comments on commit d65a627

Please sign in to comment.