]> Git — Sourcephile - sourcephile-nix.git/blob - nixos/modules/config/fonts/fontconfig.nix
syncoid: work on PR#236729
[sourcephile-nix.git] / nixos / modules / config / fonts / fontconfig.nix
1 /*
2
3 NixOS support 2 fontconfig versions, "support" and "latest".
4
5 - "latest" refers to default fontconfig package (pkgs.fontconfig).
6 configuration files are linked to /etc/fonts/VERSION/conf.d/
7 - "support" refers to supportPkg (pkgs."fontconfig_${supportVersion}").
8 configuration files are linked to /etc/fonts/conf.d/
9
10 This module generates a package containing configuration files and link it in /etc/fonts.
11
12 Fontconfig reads files in folder name / file name order, so the number prepended to the configuration file name decide the order of parsing.
13 Low number means high priority.
14
15 */
16
17 { config, pkgs, lib, ... }:
18
19 with lib;
20
21 let
22 cfg = config.fonts.fontconfig;
23
24 fcBool = x: "<bool>" + (boolToString x) + "</bool>";
25
26 # back-supported fontconfig version and package
27 # version is used for font cache generation
28 supportVersion = "210";
29 supportPkg = pkgs."fontconfig_${supportVersion}";
30
31 # latest fontconfig version and package
32 # version is used for configuration folder name, /etc/fonts/VERSION/
33 # note: format differs from supportVersion and can not be used with makeCacheConf
34 latestVersion = pkgs.fontconfig.configVersion;
35 latestPkg = pkgs.fontconfig;
36
37 # supported version fonts.conf
38 supportFontsConf = pkgs.makeFontsConf { fontconfig = supportPkg; fontDirectories = config.fonts.fonts; };
39
40 # configuration file to read fontconfig cache
41 # version dependent
42 # priority 0
43 cacheConfSupport = makeCacheConf { version = supportVersion; };
44 cacheConfLatest = makeCacheConf { };
45
46 # generate the font cache setting file for a fontconfig version
47 # use latest when no version is passed
48 # When cross-compiling, we can’t generate the cache, so we skip the
49 # <cachedir> part. fontconfig still works but is a little slower in
50 # looking things up.
51 makeCacheConf = { version ? null }:
52 let
53 fcPackage =
54 if version == null
55 then "fontconfig"
56 else "fontconfig_${version}";
57 makeCache = fontconfig: pkgs.makeFontsCache { inherit fontconfig; fontDirectories = config.fonts.fonts; };
58 cache = makeCache pkgs.${fcPackage};
59 cache32 = makeCache pkgs.pkgsi686Linux.${fcPackage};
60 in
61 pkgs.writeText "fc-00-nixos-cache.conf" ''
62 <?xml version='1.0'?>
63 <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
64 <fontconfig>
65 <!-- Font directories -->
66 ${concatStringsSep "\n" (map (font: "<dir>${font}</dir>") config.fonts.fonts)}
67 ${optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) ''
68 <!-- Pre-generated font caches -->
69 <cachedir>${cache}</cachedir>
70 ${optionalString (pkgs.stdenv.isx86_64 && cfg.cache32Bit) ''
71 <cachedir>${cache32}</cachedir>
72 ''}
73 ''}
74 </fontconfig>
75 '';
76
77 # rendering settings configuration file
78 # priority 10
79 renderConf = pkgs.writeText "fc-10-nixos-rendering.conf" ''
80 <?xml version='1.0'?>
81 <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
82 <fontconfig>
83
84 <!-- Default rendering settings -->
85 <match target="pattern">
86 <edit mode="append" name="hinting">
87 ${fcBool cfg.hinting.enable}
88 </edit>
89 <edit mode="append" name="autohint">
90 ${fcBool cfg.hinting.autohint}
91 </edit>
92 <edit mode="append" name="hintstyle">
93 <const>hintslight</const>
94 </edit>
95 <edit mode="append" name="antialias">
96 ${fcBool cfg.antialias}
97 </edit>
98 <edit mode="append" name="rgba">
99 <const>${cfg.subpixel.rgba}</const>
100 </edit>
101 <edit mode="append" name="lcdfilter">
102 <const>lcd${cfg.subpixel.lcdfilter}</const>
103 </edit>
104 </match>
105
106 ${optionalString (cfg.dpi != 0) ''
107 <match target="pattern">
108 <edit name="dpi" mode="assign">
109 <double>${toString cfg.dpi}</double>
110 </edit>
111 </match>
112 ''}
113
114 </fontconfig>
115 '';
116
117 # local configuration file
118 localConf = pkgs.writeText "fc-local.conf" cfg.localConf;
119
120 # default fonts configuration file
121 # priority 52
122 defaultFontsConf =
123 let
124 genDefault = fonts: name:
125 optionalString (fonts != [ ]) ''
126 <alias binding="same">
127 <family>${name}</family>
128 <prefer>
129 ${concatStringsSep ""
130 (map (font: ''
131 <family>${font}</family>
132 '') fonts)}
133 </prefer>
134 </alias>
135 '';
136 in
137 pkgs.writeText "fc-52-nixos-default-fonts.conf" ''
138 <?xml version='1.0'?>
139 <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
140 <fontconfig>
141
142 <!-- Default fonts -->
143 ${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
144
145 ${genDefault cfg.defaultFonts.serif "serif"}
146
147 ${genDefault cfg.defaultFonts.monospace "monospace"}
148
149 ${genDefault cfg.defaultFonts.emoji "emoji"}
150
151 </fontconfig>
152 '';
153
154 # bitmap font options
155 # priority 53
156 rejectBitmaps = pkgs.writeText "fc-53-no-bitmaps.conf" ''
157 <?xml version="1.0"?>
158 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
159 <fontconfig>
160
161 ${optionalString (!cfg.allowBitmaps) ''
162 <!-- Reject bitmap fonts -->
163 <selectfont>
164 <rejectfont>
165 <pattern>
166 <patelt name="scalable"><bool>false</bool></patelt>
167 </pattern>
168 </rejectfont>
169 </selectfont>
170 ''}
171
172 <!-- Use embedded bitmaps in fonts like Calibri? -->
173 <match target="font">
174 <edit name="embeddedbitmap" mode="assign">
175 ${fcBool cfg.useEmbeddedBitmaps}
176 </edit>
177 </match>
178
179 </fontconfig>
180 '';
181
182 # reject Type 1 fonts
183 # priority 53
184 rejectType1 = pkgs.writeText "fc-53-nixos-reject-type1.conf" ''
185 <?xml version="1.0"?>
186 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
187 <fontconfig>
188
189 <!-- Reject Type 1 fonts -->
190 <selectfont>
191 <rejectfont>
192 <pattern>
193 <patelt name="fontformat"><string>Type 1</string></patelt>
194 </pattern>
195 </rejectfont>
196 </selectfont>
197
198 </fontconfig>
199 '';
200
201 # fontconfig configuration package
202 confPkg = pkgs.runCommand "fontconfig-conf"
203 {
204 preferLocalBuild = true;
205 } ''
206 support_folder=$out/etc/fonts/conf.d
207 latest_folder=$out/etc/fonts/${latestVersion}/conf.d
208
209 mkdir -p $support_folder
210 mkdir -p $latest_folder
211
212 # fonts.conf
213 ln -s ${supportFontsConf} $support_folder/../fonts.conf
214 ln -s ${latestPkg.out}/etc/fonts/fonts.conf \
215 $latest_folder/../fonts.conf
216
217 # fontconfig default config files
218 ln -s ${supportPkg.out}/etc/fonts/conf.d/*.conf \
219 $support_folder/
220 ln -s ${latestPkg.out}/etc/fonts/conf.d/*.conf \
221 $latest_folder/
222
223 # update latest 51-local.conf path to look at the latest local.conf
224 rm $latest_folder/51-local.conf
225
226 substitute ${latestPkg.out}/etc/fonts/conf.d/51-local.conf \
227 $latest_folder/51-local.conf \
228 --replace local.conf /etc/fonts/${latestVersion}/local.conf
229
230 # 00-nixos-cache.conf
231 ln -s ${cacheConfSupport} \
232 $support_folder/00-nixos-cache.conf
233 ln -s ${cacheConfLatest} $latest_folder/00-nixos-cache.conf
234
235 # 10-nixos-rendering.conf
236 ln -s ${renderConf} $support_folder/10-nixos-rendering.conf
237 ln -s ${renderConf} $latest_folder/10-nixos-rendering.conf
238
239 # 50-user.conf
240 ${optionalString (!cfg.includeUserConf) ''
241 rm $support_folder/50-user.conf
242 rm $latest_folder/50-user.conf
243 ''}
244
245 # local.conf (indirect priority 51)
246 ${optionalString (cfg.localConf != "") ''
247 ln -s ${localConf} $support_folder/../local.conf
248 ln -s ${localConf} $latest_folder/../local.conf
249 ''}
250
251 # 52-nixos-default-fonts.conf
252 ln -s ${defaultFontsConf} $support_folder/52-nixos-default-fonts.conf
253 ln -s ${defaultFontsConf} $latest_folder/52-nixos-default-fonts.conf
254
255 # 53-no-bitmaps.conf
256 ln -s ${rejectBitmaps} $support_folder/53-no-bitmaps.conf
257 ln -s ${rejectBitmaps} $latest_folder/53-no-bitmaps.conf
258
259 ${optionalString (!cfg.allowType1) ''
260 # 53-nixos-reject-type1.conf
261 ln -s ${rejectType1} $support_folder/53-nixos-reject-type1.conf
262 ln -s ${rejectType1} $latest_folder/53-nixos-reject-type1.conf
263 ''}
264 '';
265
266 # Package with configuration files
267 # this merge all the packages in the fonts.fontconfig.confPackages list
268 fontconfigEtc = pkgs.buildEnv {
269 name = "fontconfig-etc";
270 paths = cfg.confPackages;
271 ignoreCollisions = true;
272 };
273 in
274 {
275 imports = [
276 (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowBitmaps" ] [ "fonts" "fontconfig" "allowBitmaps" ])
277 (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowType1" ] [ "fonts" "fontconfig" "allowType1" ])
278 (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "useEmbeddedBitmaps" ] [ "fonts" "fontconfig" "useEmbeddedBitmaps" ])
279 (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "fonts" "fontconfig" "forceAutohint" ])
280 (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ])
281 (mkRemovedOptionModule [ "fonts" "fontconfig" "hinting" "style" ] "")
282 (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "")
283 (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "")
284 ] ++ lib.forEach [ "enable" "substitutions" "preset" ]
285 (opt: lib.mkRemovedOptionModule [ "fonts" "fontconfig" "ultimate" "${opt}" ] ''
286 The fonts.fontconfig.ultimate module and configuration is obsolete.
287 The repository has since been archived and activity has ceased.
288 https://github.com/bohoomil/fontconfig-ultimate/issues/171.
289 No action should be needed for font configuration, as the fonts.fontconfig
290 module is already used by default.
291 '');
292
293 options = {
294
295 fonts = {
296
297 fontconfig = {
298 enable = mkOption {
299 type = types.bool;
300 default = true;
301 description = ''
302 If enabled, a Fontconfig configuration file will be built
303 pointing to a set of default fonts. If you don't care about
304 running X11 applications or any other program that uses
305 Fontconfig, you can turn this option off and prevent a
306 dependency on all those fonts.
307 '';
308 };
309
310 confPackages = mkOption {
311 internal = true;
312 type = with types; listOf path;
313 default = [ ];
314 description = ''
315 Fontconfig configuration packages.
316 '';
317 };
318
319 antialias = mkOption {
320 type = types.bool;
321 default = true;
322 description = ''
323 Enable font antialiasing. At high resolution (> 200 DPI),
324 antialiasing has no visible effect; users of such displays may want
325 to disable this option.
326 '';
327 };
328
329 dpi = mkOption {
330 type = types.int;
331 default = 0;
332 description = ''
333 Force DPI setting. Setting to <literal>0</literal> disables DPI
334 forcing; the DPI detected for the display will be used.
335 '';
336 };
337
338 localConf = mkOption {
339 type = types.lines;
340 default = "";
341 description = ''
342 System-wide customization file contents, has higher priority than
343 <literal>defaultFonts</literal> settings.
344 '';
345 };
346
347 defaultFonts = {
348 monospace = mkOption {
349 type = types.listOf types.str;
350 default = [ "DejaVu Sans Mono" ];
351 description = ''
352 System-wide default monospace font(s). Multiple fonts may be
353 listed in case multiple languages must be supported.
354 '';
355 };
356
357 sansSerif = mkOption {
358 type = types.listOf types.str;
359 default = [ "DejaVu Sans" ];
360 description = ''
361 System-wide default sans serif font(s). Multiple fonts may be
362 listed in case multiple languages must be supported.
363 '';
364 };
365
366 serif = mkOption {
367 type = types.listOf types.str;
368 default = [ "DejaVu Serif" ];
369 description = ''
370 System-wide default serif font(s). Multiple fonts may be listed
371 in case multiple languages must be supported.
372 '';
373 };
374
375 emoji = mkOption {
376 type = types.listOf types.str;
377 default = [ "Noto Color Emoji" ];
378 description = ''
379 System-wide default emoji font(s). Multiple fonts may be listed
380 in case a font does not support all emoji.
381
382 Note that fontconfig matches color emoji fonts preferentially,
383 so if you want to use a black and white font while having
384 a color font installed (eg. Noto Color Emoji installed alongside
385 Noto Emoji), fontconfig will still choose the color font even
386 when it is later in the list.
387 '';
388 };
389 };
390
391 hinting = {
392 enable = mkOption {
393 type = types.bool;
394 default = true;
395 description = ''
396 Enable font hinting. Hinting aligns glyphs to pixel boundaries to
397 improve rendering sharpness at low resolution. At high resolution
398 (> 200 dpi) hinting will do nothing (at best); users of such
399 displays may want to disable this option.
400 '';
401 };
402
403 autohint = mkOption {
404 type = types.bool;
405 default = false;
406 description = ''
407 Enable the autohinter in place of the default interpreter.
408 The results are usually lower quality than correctly-hinted
409 fonts, but better than unhinted fonts.
410 '';
411 };
412 };
413
414 includeUserConf = mkOption {
415 type = types.bool;
416 default = true;
417 description = ''
418 Include the user configuration from
419 <filename>~/.config/fontconfig/fonts.conf</filename> or
420 <filename>~/.config/fontconfig/conf.d</filename>.
421 '';
422 };
423
424 subpixel = {
425
426 rgba = mkOption {
427 default = "rgb";
428 type = types.enum [ "rgb" "bgr" "vrgb" "vbgr" "none" ];
429 description = ''
430 Subpixel order. The overwhelming majority of displays are
431 <literal>rgb</literal> in their normal orientation. Select
432 <literal>vrgb</literal> for mounting such a display 90 degrees
433 clockwise from its normal orientation or <literal>vbgr</literal>
434 for mounting 90 degrees counter-clockwise. Select
435 <literal>bgr</literal> in the unlikely event of mounting 180
436 degrees from the normal orientation. Reverse these directions in
437 the improbable event that the display's native subpixel order is
438 <literal>bgr</literal>.
439 '';
440 };
441
442 lcdfilter = mkOption {
443 default = "default";
444 type = types.enum [ "none" "default" "light" "legacy" ];
445 description = ''
446 FreeType LCD filter. At high resolution (> 200 DPI), LCD filtering
447 has no visible effect; users of such displays may want to select
448 <literal>none</literal>.
449 '';
450 };
451
452 };
453
454 cache32Bit = mkOption {
455 default = false;
456 type = types.bool;
457 description = ''
458 Generate system fonts cache for 32-bit applications.
459 '';
460 };
461
462 allowBitmaps = mkOption {
463 type = types.bool;
464 default = true;
465 description = ''
466 Allow bitmap fonts. Set to <literal>false</literal> to ban all
467 bitmap fonts.
468 '';
469 };
470
471 allowType1 = mkOption {
472 type = types.bool;
473 default = false;
474 description = ''
475 Allow Type-1 fonts. Default is <literal>false</literal> because of
476 poor rendering.
477 '';
478 };
479
480 useEmbeddedBitmaps = mkOption {
481 type = types.bool;
482 default = false;
483 description = ''Use embedded bitmaps in fonts like Calibri.'';
484 };
485
486 };
487
488 };
489
490 };
491 config = mkMerge [
492 (mkIf cfg.enable {
493 environment.systemPackages = [ pkgs.fontconfig ];
494 environment.etc.fonts.source = "${fontconfigEtc}/etc/fonts/";
495 security.apparmor.includes."abstractions/fonts" = ''
496 # fonts.conf
497 r ${supportFontsConf}
498 r ${latestPkg.out}/etc/fonts/fonts.conf
499
500 # fontconfig default config files
501 r ${supportPkg.out}/etc/fonts/conf.d/*.conf,
502 r ${latestPkg.out}/etc/fonts/conf.d/*.conf,
503
504 substitute ${latestPkg.out}/etc/fonts/conf.d/51-local.conf \
505 $latest_folder/51-local.conf \
506 --replace local.conf /etc/fonts/${latestVersion}/local.conf
507
508 # 00-nixos-cache.conf
509 r ${cacheConfSupport},
510 r ${cacheConfLatest},
511
512 # 10-nixos-rendering.conf
513 r ${renderConf},
514
515 # local.conf (indirect priority 51)
516 ${optionalString (cfg.localConf != "") ''
517 r ${localConf},
518 ''}
519
520 # 52-nixos-default-fonts.conf
521 r ${defaultFontsConf},
522
523 # 53-no-bitmaps.conf
524 r ${rejectBitmaps},
525
526 ${optionalString (!cfg.allowType1) ''
527 # 53-nixos-reject-type1.conf
528 r ${rejectType1},
529 ''}
530 '';
531 })
532 (mkIf (cfg.enable && !cfg.penultimate.enable) {
533 fonts.fontconfig.confPackages = [ confPkg ];
534 })
535 ];
536
537 }