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

noto-fonts: 2020-01-23 -> unstable-2022-04-25 and other changes #170355

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions nixos/tests/noto-fonts.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {

testScript =
# extracted from http://www.clagnut.com/blog/2380/
# emoji are from Unicode 14 (latest standard)
let testText = builtins.toFile "test.txt" ''
the quick brown fox jumps over the lazy dog
視野無限廣,窗外有藍天
Eĥoŝanĝo ĉiuĵaŭde.
いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす
다람쥐 헌 쳇바퀴에 타고파
中国智造,慧及全球
🫠🫣🫱🏻‍🫲🏿
''; in
''
machine.wait_for_x()
Expand Down
156 changes: 156 additions & 0 deletions pkgs/data/fonts/noto-fonts/analyze_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import csv
import re
from collections import defaultdict

# fc-scan ./hinted ./unhinted -f '"%{fullname[0]}","%{file}"\n' > scan.csv

blacklist = [
# provides "Noto S Display, M" while main font provides "Noto S, Display M".
# package both by blacklisting and force-adding Display fonts later
# https://github.com/googlefonts/noto-fonts/issues/2315
r"\./unhinted/(slim-)?variable-ttf/NotoSansDisplay-Italic-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSansDisplay-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSerifDisplay-VF\.ttf",
# provides "Noto Sans Display X, Regular" instead of "Noto Sans Display, X"
# https://github.com/googlefonts/noto-fonts/issues/2315
r"\./unhinted/otf/NotoSansDisplay/NotoSansDisplay-[A-Za-z]+\.otf",
# provides "Noto Sans X" instead of "Noto Sans X UI"
# https://github.com/googlefonts/noto-fonts/issues/2316
r"\./unhinted/(slim-)?variable-ttf/NotoSansKannadaUI-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSansMalayalamUI-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSansSinhalaUI-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSansTamilUI-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSansTeluguUI-VF\.ttf",
# extraneous files
# comment in https://github.com/googlefonts/noto-fonts/issues/2316
r"\./unhinted/(slim-)?variable-ttf/NotoSansTamil-android-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSansTamilUI-android-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSansTamilUI-VF-torecover\.ttf",
# provides "FontName" instead of "Font Name"
# https://github.com/googlefonts/noto-fonts/issues/2317
r"\./unhinted/(slim-)?variable-ttf/NotoSansMeeteiMayek-VF\.ttf",
r"\./unhinted/(slim-)?variable-ttf/NotoSerifTamilSlanted-VF\.ttf",
# font names are missing Bold, Italic, etc.
# https://github.com/googlefonts/noto-fonts/issues/2317
r"\./unhinted/(slim-)?variable-ttf/NotoSansHanifiRohingya-VF\.ttf",
# duplicate fonts in NotoSansTifinagh
# https://github.com/googlefonts/noto-fonts/issues/2326
r"\./unhinted/otf/NotoSansTifinagh/NotoSansTifinagh[A-Z].*\.otf"
]

blacklist = list(map(re.compile, blacklist))

class Font:
def __init__(self):
self.hinted_ttf = None
self.unhinted_ttf = None
self.otf = None
self.vf = None
self.slimvf = None
self.extra = None

fonts = defaultdict(Font)

# KDE uses Light/LightItalic, so keep those in the main package, see
# https://mail.kde.org/pipermail/distributions/2017-November/000706.html
# https://mail.kde.org/pipermail/distributions/2017-November/000709.html
extrafontpattern = re.compile(r".*(Black|Condensed|Extra|Medium|Semi|Thin).*")

with open('scan.csv', newline='') as csvfile:
scanreader = csv.reader(csvfile, delimiter=',', quotechar='"')
for row in scanreader:
[font, fontfile] = row
if any(rgx.match(fontfile) for rgx in blacklist):
continue
if fontfile.startswith("./hinted/ttf"):
if fonts[font].hinted_ttf and fonts[font].hinted_ttf != fontfile:
print("duplicate httf", font, ":", fonts[font].hinted_ttf, "and", fontfile)
fonts[font].hinted_ttf = fontfile
elif fontfile.startswith("./unhinted/ttf"):
if fonts[font].unhinted_ttf and fonts[font].unhinted_ttf != fontfile:
print("duplicate uttf", font, ":", fonts[font].unhinted_ttf, "and", fontfile)
fonts[font].unhinted_ttf = fontfile
elif fontfile.startswith("./unhinted/otf"):
if fonts[font].otf and fonts[font].otf != fontfile:
print("duplicate otf", font, ":", fonts[font].otf, "and", fontfile)
fonts[font].otf = fontfile
elif fontfile.startswith("./unhinted/variable-ttf"):
if fonts[font].vf and fonts[font].vf != fontfile and font != "":
print("duplicate vf", font, ":", fonts[font].vf, "and", fontfile)
fonts[font].vf = fontfile
elif fontfile.startswith("./unhinted/slim-variable-ttf"):
if fonts[font].slimvf and fonts[font].slimvf != fontfile and font != "":
print("duplicate slim", font, ":", fonts[font].slimvf, "and", fontfile)
fonts[font].slimvf = fontfile
else:
print("Unknown font directory: ", ', '.join(row))
raise NotImplementedError

fonts[font].extra = extrafontpattern.match(font) != None or font == ""

# inconsistent names, see https://github.com/googlefonts/noto-fonts/issues/2317
# for these names the VF names seem acceptable
lightlightpattern = re.compile(r"Noto Sans Hebrew (New )?Light Light")
hmongpattern = re.compile(r"Noto Serif Nyiakeng Puachue Hmong .+")

# compute noto-font files

mode = "vf" # "otf" "slimvf" "vf"
modeextra = "vf" # "otf" "vf"

# force-add Display VF's to file list, see above
# https://github.com/googlefonts/noto-fonts/issues/2315
filelist = set(
["./unhinted/variable-ttf/NotoSansDisplay-Italic-VF.ttf",
"./unhinted/variable-ttf/NotoSansDisplay-VF.ttf",
"./unhinted/variable-ttf/NotoSerifDisplay-VF.ttf"])

for name, font in fonts.items():
if font.extra:
continue

if font.vf and mode == "vf":
if not font.otf and name != "" and not lightlightpattern.match(name) and not hmongpattern.match(name):
print("missing otf:", name, ", ", font.vf)
continue
filelist.add(font.vf)
elif font.slimvf and mode == "slimvf":
if not font.otf and font.slimvf != "":
print("missing otf:", name, ", ", font.slimvf)
continue
filelist.add(font.slimvf)
elif font.otf:
filelist.add(font.otf)
elif font.vf:
continue
else:
print("weird font: ", name, ", ", font)
raise NotImplementedError

with open('noto_fonts_list.txt', 'w') as f:
for item in filelist:
f.write("%s\n" % item)

extra_list = set()

for name, font in fonts.items():
if font.vf in filelist or font.slimvf in filelist or font.otf in filelist:
continue

if font.vf and modeextra != "otf":
if not font.otf and name != "" and not lightlightpattern.match(name) and not hmongpattern.match(name):
print("missing otf:", name, ", ", font.vf)
continue
extra_list.add(font.vf)
elif font.otf:
extra_list.add(font.otf)
elif font.vf:
continue
else:
print("weird font: ", name, ", ", font)
raise NotImplementedError

with open('noto_extra_list.txt', 'w') as f:
for item in extra_list:
f.write("%s\n" % item)

61 changes: 37 additions & 24 deletions pkgs/data/fonts/noto-fonts/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,44 @@
, imagemagick
, zopfli
, buildPackages
, fontconfig
, python3
}:

let
mkNoto = { pname, weights }:
noto-pkg =
stdenvNoCC.mkDerivation {
inherit pname;
version = "2020-01-23";
pname = "noto-fonts";
version = "unstable-2022-04-25";

src = fetchFromGitHub {
owner = "googlefonts";
repo = "noto-fonts";
rev = "f4726a2ec36169abd02a6d8abe67c8ff0236f6d8";
sha256 = "0zc1r7zph62qmvzxqfflsprazjf6x1qnwc2ma27kyzh6v36gaykw";
rev = "a19de47f845dbd4c61b884c7ff90ce993555d05d";
sparseCheckout = ''
unhinted/otf
unhinted/variable-ttf
'';
hash = "sha256-7Jzo7402CiOcn2q++zbAzn2tP/y2x7QJuwjcP1NoyLQ=";
};

analyzeScan = ./analyze_scan.py;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment what this does roughly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reads all the font information from fc-scan and figures out which fonts are included in the variable fonts and which aren't and need the OTF version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There probably is a way to do it with shell scripting but my head hurt thinking about it.


nativeBuildInputs = [ buildPackages.fontconfig.bin buildPackages.python3 ];

outputs = [ "out" "extra" ];

installPhase = ''
# We copy in reverse preference order -- unhinted first, then
# hinted -- to get the "best" version of each font while
# maintaining maximum coverage.
#
# TODO: install OpenType, variable versions?
local out_ttf=$out/share/fonts/truetype/noto
install -m444 -Dt $out_ttf phaseIII_only/unhinted/ttf/*/*-${weights}.ttf
install -m444 -Dt $out_ttf phaseIII_only/hinted/ttf/*/*-${weights}.ttf
install -m444 -Dt $out_ttf unhinted/*/*-${weights}.ttf
install -m444 -Dt $out_ttf hinted/*/*-${weights}.ttf
fc-scan ./unhinted -f '"%{fullname[0]}","%{file}"\n' > scan.csv
python $analyzeScan
local out_ttf=$out/share/fonts/google-noto
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fonts are no longer installed to the truetype subdirectory. This seems like it would break at least koreader.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Freetype scans all subdirectories regardless of name so the directory names are arbitrary. koreader uses Freetype so should work fine. Certainly Fedora doesn't bother with the truetype directory anymore, see e.g. Droid sans. Also it would be misleading in this case to call them "truetype" since they are a mixture of opentype (otf) and variable TTFs.

The more questionable aspect is whether koreader supports variable fonts. It seems to have the individual TTF file names names hard-coded. When I run koreader it crashes with the message frontend/ui/font.lua:353: attempt to index local 'face' (a nil value). This could be because it doesn't like the variable fonts I have installed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my comment was more (or less?) concrete than that: The koreader derivation assumes this at the moment which should be easy to fix:

for i in ${noto-fonts}/share/fonts/truetype/noto/*; do
ln -s "$i" $out/lib/koreader/fonts/noto/
done

Copy link
Contributor Author

@Mathnerd314 Mathnerd314 May 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. koreader should probably fetch the noto fonts itself in a private derivation, like OnlyOffice. Particularly it needs only a few languages and font variants, as compared to the main noto-fonts package which provides all of them. cc @contrun and @neonfuz who can write that patch. (koreader crashes for me so I don't think I can do it)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@a-m-joseph Any chance you could look into this, seeing as you recently touched koreader?

Copy link

@ghost ghost Jun 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@a-m-joseph Any chance you could look into this, seeing as you recently touched koreader?

I can try.

Other than pragmata pro (worth every penny) I don't know much about fonts, and know even less about unicode emojii :)

Oh sorry by "this" I thought you meant the whole PR rather than the possible koreader breakage. Yes, I will figure out how to keep koreader happy.

Copy link

@ghost ghost Jun 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more questionable aspect is whether koreader supports variable fonts. It seems to have the individual TTF file names names hard-coded. When I run koreader it crashes with the message frontend/ui/font.lua:353: attempt to index local 'face' (a nil value). This could be because it doesn't like the variable fonts I have installed.

No, that means it couldn't find the fonts.

I get the same error above with this PR.

If I revert this PR I don't get the error.

Ah, I see. koreader should probably fetch the noto fonts itself in a private derivation

Yeah, I'm not excited about this but I don't see any other way considering the hardcoded font names in koreader. That project already has an astonishing level of pinning/vendoring going on. I will write the PR to remove the koreader->noto-fonts dependency and have koreader do its own separate fetchurl to get the fonts. I'm leaving town tomorrow morning and if I try to get it done before then I will end up doing a sloppy/rushed job. This will need to wait until mid/late next week. Feel free to ping me or open a bug and assign it to me as a reminder.

My interest in the nixpkgs koreader expression is partly to be able to hack on koreader using nixpkgs for the builds, but also partly to see if nixpkgs can offer a better way to manage the 50+ projects they currently pull in -- sort of analogous to NixWRT. I'm starting to realize that koreader is almost a tiny Linux distribution, just like OpenWRT is. Unfortunately just convincing their CMake machinery to use pre-downloaded tarballs (instead of insisting on downloading them itself) has been so difficult that my enthusiasm for the endeavor is waning.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately just convincing their CMake machinery to use pre-downloaded tarballs (instead of insisting on downloading them itself) has been so difficult

I've finally made some real progress on this. Hope to have a draft PR shortly.

Copy link

@ghost ghost Jun 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like it would break at least koreader.

TL;DR: this problem disappears when we we build koreader from source instead of trying to rebundle the Debian binaries.

It turns out that nixpkgs' koreader/default.nix having a dependency upon nixpkgs' noto-fonts is 100% an artifact of the fact that koreader/default.nix is not much more than dpkg -x. The problem disappears as soon as we build koreader from source.

Koreader has a git submodule containing the exact font files they expect (since they hardwire so many things, like the fonts' filenames).

These fonts are, for some reason, not included in the .deb archives that our current koreader/default.nix is using. I suppose this could be in anticipation of Debian policy, although koreader has never been carried by Debian and would need a lot of other more drastic changes in order for them to accept it. So I really don't know why the fonts get dropped when the deb is built.

In any event: my built-from-source koreader solves the problem here.

while read p; do
install -m444 -Dt $out_ttf "$p"
done <noto_fonts_list.txt
local extra_ttf=$extra/share/fonts/google-noto
while read p; do
install -m444 -Dt $extra_ttf "$p"
done <noto_extra_list.txt
'';

meta = with lib; {
Expand All @@ -54,12 +66,18 @@ let
Google’s goal is to see “no more tofu”. Noto has multiple styles and
weights, and freely available to all.

noto-fonts contains Regular, Bold, and Light weights and Italic style,
and noto-fonts-extra contains the rest.

This package also includes the Arimo, Cousine, and Tinos fonts.
'';
license = licenses.ofl;
platforms = platforms.all;
maintainers = with maintainers; [ mathnerd314 emily ];
};

passthru.tests.noto-fonts = nixosTests.noto-fonts;

};

mkNotoCJK = { typeface, version, rev, sha256 }:
Expand Down Expand Up @@ -103,15 +121,8 @@ let
in

{
noto-fonts = mkNoto {
pname = "noto-fonts";
weights = "{Regular,Bold,Light,Italic,BoldItalic,LightItalic}";
};

noto-fonts-extra = mkNoto {
pname = "noto-fonts-extra";
weights = "{Black,Condensed,Extra,Medium,Semi,Thin}*";
};
noto-fonts = noto-pkg.out;
noto-fonts-extra = noto-pkg.extra;

noto-fonts-cjk-sans = mkNotoCJK {
typeface = "Sans";
Expand Down Expand Up @@ -182,6 +193,8 @@ in
platforms = platforms.all;
maintainers = with maintainers; [ mathnerd314 sternenseemann ];
};

passthru.tests.noto-fonts = nixosTests.noto-fonts;
};

noto-fonts-emoji-blob-bin =
Expand Down