python313Packages.pyais: 2.8.3 -> 2.8.4 (#378375)
[NixPkgs.git] / nixos / modules / config / fonts / fontconfig.nix
blob984daec204315dc399e28bb83d1f80810b9b120d
1 /*
2   Configuration files are linked to /etc/fonts/conf.d/
4   This module generates a package containing configuration files and link it in /etc/fonts.
6   Fontconfig reads files in folder name / file name order, so the number prepended to the configuration file name decide the order of parsing.
7   Low number means high priority.
9   NOTE: Please take extreme care when adjusting the default settings of this module.
10   People care a lot, and I mean A LOT, about their font rendering, and you will be
11   The Person That Broke It if it changes in a way people don't like.
13   See prior art:
14   - https://github.com/NixOS/nixpkgs/pull/194594
15   - https://github.com/NixOS/nixpkgs/pull/222236
16   - https://github.com/NixOS/nixpkgs/pull/222689
18   And do not repeat our mistakes.
20   - @K900, March 2023
24   config,
25   pkgs,
26   lib,
27   ...
29 let
30   cfg = config.fonts.fontconfig;
32   fcBool = x: "<bool>" + (lib.boolToString x) + "</bool>";
33   pkg = pkgs.fontconfig;
35   # configuration file to read fontconfig cache
36   # priority 0
37   cacheConf = makeCacheConf { };
39   # generate the font cache setting file
40   # When cross-compiling, we can’t generate the cache, so we skip the
41   # <cachedir> part. fontconfig still works but is a little slower in
42   # looking things up.
43   makeCacheConf =
44     { }:
45     let
46       makeCache =
47         fontconfig:
48         pkgs.makeFontsCache {
49           inherit fontconfig;
50           fontDirectories = config.fonts.packages;
51         };
52       cache = makeCache pkgs.fontconfig;
53       cache32 = makeCache pkgs.pkgsi686Linux.fontconfig;
54     in
55     pkgs.writeText "fc-00-nixos-cache.conf" ''
56       <?xml version='1.0'?>
57       <!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
58       <fontconfig>
59         <!-- Font directories -->
60         ${lib.concatStringsSep "\n" (map (font: "<dir>${font}</dir>") config.fonts.packages)}
61         ${lib.optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) ''
62           <!-- Pre-generated font caches -->
63           <cachedir>${cache}</cachedir>
64           ${lib.optionalString (pkgs.stdenv.hostPlatform.isx86_64 && cfg.cache32Bit) ''
65             <cachedir>${cache32}</cachedir>
66           ''}
67         ''}
68       </fontconfig>
69     '';
71   # rendering settings configuration file
72   # priority 10
73   renderConf = pkgs.writeText "fc-10-nixos-rendering.conf" ''
74     <?xml version='1.0'?>
75     <!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
76     <fontconfig>
78       <!-- Default rendering settings -->
79       <match target="pattern">
80         <edit mode="append" name="hinting">
81           ${fcBool cfg.hinting.enable}
82         </edit>
83         <edit mode="append" name="autohint">
84           ${fcBool cfg.hinting.autohint}
85         </edit>
86       </match>
88     </fontconfig>
89   '';
91   # local configuration file
92   localConf = pkgs.writeText "fc-local.conf" cfg.localConf;
94   # default fonts configuration file
95   # priority 52
96   defaultFontsConf =
97     let
98       genDefault =
99         fonts: name:
100         lib.optionalString (fonts != [ ]) ''
101           <alias binding="same">
102             <family>${name}</family>
103             <prefer>
104             ${lib.concatStringsSep "" (
105               map (font: ''
106                 <family>${font}</family>
107               '') fonts
108             )}
109             </prefer>
110           </alias>
111         '';
112     in
113     pkgs.writeText "fc-52-nixos-default-fonts.conf" ''
114       <?xml version='1.0'?>
115       <!DOCTYPE fontconfig SYSTEM 'urn:fontconfig:fonts.dtd'>
116       <fontconfig>
118         <!-- Default fonts -->
119         ${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
121         ${genDefault cfg.defaultFonts.serif "serif"}
123         ${genDefault cfg.defaultFonts.monospace "monospace"}
125         ${genDefault cfg.defaultFonts.emoji "emoji"}
127       </fontconfig>
128     '';
130   # bitmap font options
131   # priority 53
132   rejectBitmaps = pkgs.writeText "fc-53-no-bitmaps.conf" ''
133     <?xml version="1.0"?>
134     <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
135     <fontconfig>
137     ${lib.optionalString (!cfg.allowBitmaps) ''
138       <!-- Reject bitmap fonts -->
139       <selectfont>
140         <rejectfont>
141           <pattern>
142             <patelt name="scalable"><bool>false</bool></patelt>
143           </pattern>
144         </rejectfont>
145       </selectfont>
146     ''}
148     <!-- Use embedded bitmaps in fonts like Calibri? -->
149     <match target="font">
150       <edit name="embeddedbitmap" mode="assign">
151         ${fcBool cfg.useEmbeddedBitmaps}
152       </edit>
153     </match>
155     </fontconfig>
156   '';
158   # reject Type 1 fonts
159   # priority 53
160   rejectType1 = pkgs.writeText "fc-53-nixos-reject-type1.conf" ''
161     <?xml version="1.0"?>
162     <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
163     <fontconfig>
165     <!-- Reject Type 1 fonts -->
166     <selectfont>
167       <rejectfont>
168         <pattern>
169           <patelt name="fontformat"><string>Type 1</string></patelt>
170         </pattern>
171       </rejectfont>
172     </selectfont>
174     </fontconfig>
175   '';
177   # Replace default linked config with a different variant
178   replaceDefaultConfig = defaultConfig: newConfig: ''
179     rm $dst/${defaultConfig}
180     ln -s ${pkg.out}/share/fontconfig/conf.avail/${newConfig} \
181           $dst/
182   '';
184   # fontconfig configuration package
185   confPkg =
186     pkgs.runCommand "fontconfig-conf"
187       {
188         preferLocalBuild = true;
189       }
190       ''
191         dst=$out/etc/fonts/conf.d
192         mkdir -p $dst
194         # fonts.conf
195         ln -s ${pkg.out}/etc/fonts/fonts.conf \
196               $dst/../fonts.conf
197         # TODO: remove this legacy symlink once people stop using packages built before #95358 was merged
198         mkdir -p $out/etc/fonts/2.11
199         ln -s /etc/fonts/fonts.conf \
200               $out/etc/fonts/2.11/fonts.conf
202         # fontconfig default config files
203         ln -s ${pkg.out}/etc/fonts/conf.d/*.conf \
204               $dst/
206         ${lib.optionalString (!cfg.antialias) (
207           replaceDefaultConfig "10-yes-antialias.conf" "10-no-antialias.conf"
208         )}
210         ${lib.optionalString (cfg.hinting.style != "slight") (
211           replaceDefaultConfig "10-hinting-slight.conf" "10-hinting-${cfg.hinting.style}.conf"
212         )}
214         ${lib.optionalString (cfg.subpixel.rgba != "none") (
215           replaceDefaultConfig "10-sub-pixel-none.conf" "10-sub-pixel-${cfg.subpixel.rgba}.conf"
216         )}
218         ${lib.optionalString (cfg.subpixel.lcdfilter != "default") (
219           replaceDefaultConfig "11-lcdfilter-default.conf" "11-lcdfilter-${cfg.subpixel.lcdfilter}.conf"
220         )}
222         # 00-nixos-cache.conf
223         ln -s ${cacheConf}  $dst/00-nixos-cache.conf
225         # 10-nixos-rendering.conf
226         ln -s ${renderConf}       $dst/10-nixos-rendering.conf
228         # 50-user.conf
229         ${lib.optionalString (!cfg.includeUserConf) ''
230           rm $dst/50-user.conf
231         ''}
233         # local.conf (indirect priority 51)
234         ${lib.optionalString (cfg.localConf != "") ''
235           ln -s ${localConf}        $dst/../local.conf
236         ''}
238         # 52-nixos-default-fonts.conf
239         ln -s ${defaultFontsConf} $dst/52-nixos-default-fonts.conf
241         # 53-no-bitmaps.conf
242         ln -s ${rejectBitmaps} $dst/53-no-bitmaps.conf
244         ${lib.optionalString (!cfg.allowType1) ''
245           # 53-nixos-reject-type1.conf
246           ln -s ${rejectType1} $dst/53-nixos-reject-type1.conf
247         ''}
248       '';
250   # Package with configuration files
251   # this merge all the packages in the fonts.fontconfig.confPackages list
252   fontconfigEtc = pkgs.buildEnv {
253     name = "fontconfig-etc";
254     paths = cfg.confPackages;
255     ignoreCollisions = true;
256   };
258   fontconfigNote = "Consider manually configuring fonts.fontconfig according to personal preference.";
261   imports =
262     [
263       (lib.mkRenamedOptionModule
264         [ "fonts" "fontconfig" "ultimate" "allowBitmaps" ]
265         [ "fonts" "fontconfig" "allowBitmaps" ]
266       )
267       (lib.mkRenamedOptionModule
268         [ "fonts" "fontconfig" "ultimate" "allowType1" ]
269         [ "fonts" "fontconfig" "allowType1" ]
270       )
271       (lib.mkRenamedOptionModule
272         [ "fonts" "fontconfig" "ultimate" "useEmbeddedBitmaps" ]
273         [ "fonts" "fontconfig" "useEmbeddedBitmaps" ]
274       )
275       (lib.mkRenamedOptionModule
276         [ "fonts" "fontconfig" "ultimate" "forceAutohint" ]
277         [ "fonts" "fontconfig" "forceAutohint" ]
278       )
279       (lib.mkRenamedOptionModule
280         [ "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ]
281         [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ]
282       )
283       (lib.mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "")
284       (lib.mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "")
285       (lib.mkRemovedOptionModule [ "fonts" "fontconfig" "dpi" ] "Use display server-specific options")
286       (lib.mkRemovedOptionModule [ "hardware" "video" "hidpi" "enable" ] fontconfigNote)
287       (lib.mkRemovedOptionModule [ "fonts" "optimizeForVeryHighDPI" ] fontconfigNote)
288     ]
289     ++ lib.forEach [ "enable" "substitutions" "preset" ] (
290       opt:
291       lib.mkRemovedOptionModule [ "fonts" "fontconfig" "ultimate" "${opt}" ] ''
292         The fonts.fontconfig.ultimate module and configuration is obsolete.
293         The repository has since been archived and activity has ceased.
294         https://github.com/bohoomil/fontconfig-ultimate/issues/171.
295         No action should be needed for font configuration, as the fonts.fontconfig
296         module is already used by default.
297       ''
298     );
300   options = {
302     fonts = {
304       fontconfig = {
305         enable = lib.mkOption {
306           type = lib.types.bool;
307           default = true;
308           description = ''
309             If enabled, a Fontconfig configuration file will be built
310             pointing to a set of default fonts.  If you don't care about
311             running X11 applications or any other program that uses
312             Fontconfig, you can turn this option off and prevent a
313             dependency on all those fonts.
314           '';
315         };
317         confPackages = lib.mkOption {
318           internal = true;
319           type = with lib.types; listOf path;
320           default = [ ];
321           description = ''
322             Fontconfig configuration packages.
323           '';
324         };
326         antialias = lib.mkOption {
327           type = lib.types.bool;
328           default = true;
329           description = ''
330             Enable font antialiasing. At high resolution (> 200 DPI),
331             antialiasing has no visible effect; users of such displays may want
332             to disable this option.
333           '';
334         };
336         localConf = lib.mkOption {
337           type = lib.types.lines;
338           default = "";
339           description = ''
340             System-wide customization file contents, has higher priority than
341             `defaultFonts` settings.
342           '';
343         };
345         defaultFonts = {
346           monospace = lib.mkOption {
347             type = lib.types.listOf lib.types.str;
348             default = [ "DejaVu Sans Mono" ];
349             description = ''
350               System-wide default monospace font(s). Multiple fonts may be
351               listed in case multiple languages must be supported.
352             '';
353           };
355           sansSerif = lib.mkOption {
356             type = lib.types.listOf lib.types.str;
357             default = [ "DejaVu Sans" ];
358             description = ''
359               System-wide default sans serif font(s). Multiple fonts may be
360               listed in case multiple languages must be supported.
361             '';
362           };
364           serif = lib.mkOption {
365             type = lib.types.listOf lib.types.str;
366             default = [ "DejaVu Serif" ];
367             description = ''
368               System-wide default serif font(s). Multiple fonts may be listed
369               in case multiple languages must be supported.
370             '';
371           };
373           emoji = lib.mkOption {
374             type = lib.types.listOf lib.types.str;
375             default = [ "Noto Color Emoji" ];
376             description = ''
377               System-wide default emoji font(s). Multiple fonts may be listed
378               in case a font does not support all emoji.
380               Note that fontconfig matches color emoji fonts preferentially,
381               so if you want to use a black and white font while having
382               a color font installed (eg. Noto Color Emoji installed alongside
383               Noto Emoji), fontconfig will still choose the color font even
384               when it is later in the list.
385             '';
386           };
387         };
389         hinting = {
390           enable = lib.mkOption {
391             type = lib.types.bool;
392             default = true;
393             description = ''
394               Enable font hinting. Hinting aligns glyphs to pixel boundaries to
395               improve rendering sharpness at low resolution. At high resolution
396               (> 200 dpi) hinting will do nothing (at best); users of such
397               displays may want to disable this option.
398             '';
399           };
401           autohint = lib.mkOption {
402             type = lib.types.bool;
403             default = false;
404             description = ''
405               Enable the autohinter in place of the default interpreter.
406               The results are usually lower quality than correctly-hinted
407               fonts, but better than unhinted fonts.
408             '';
409           };
411           style = lib.mkOption {
412             type = lib.types.enum [
413               "none"
414               "slight"
415               "medium"
416               "full"
417             ];
418             default = "slight";
419             description = ''
420               Hintstyle is the amount of font reshaping done to line up
421               to the grid.
423               slight will make the font more fuzzy to line up to the grid but
424               will be better in retaining font shape, while full will be a
425               crisp font that aligns well to the pixel grid but will lose a
426               greater amount of font shape.
427             '';
428             apply =
429               val:
430               let
431                 from = "fonts.fontconfig.hinting.style";
432                 val' = lib.removePrefix "hint" val;
433                 warning = "The option `${from}` contains a deprecated value `${val}`. Use `${val'}` instead.";
434               in
435               lib.warnIf (lib.hasPrefix "hint" val) warning val';
436           };
437         };
439         includeUserConf = lib.mkOption {
440           type = lib.types.bool;
441           default = true;
442           description = ''
443             Include the user configuration from
444             {file}`~/.config/fontconfig/fonts.conf` or
445             {file}`~/.config/fontconfig/conf.d`.
446           '';
447         };
449         subpixel = {
451           rgba = lib.mkOption {
452             default = "none";
453             type = lib.types.enum [
454               "rgb"
455               "bgr"
456               "vrgb"
457               "vbgr"
458               "none"
459             ];
460             description = ''
461               Subpixel order. The overwhelming majority of displays are
462               `rgb` in their normal orientation. Select
463               `vrgb` for mounting such a display 90 degrees
464               clockwise from its normal orientation or `vbgr`
465               for mounting 90 degrees counter-clockwise. Select
466               `bgr` in the unlikely event of mounting 180
467               degrees from the normal orientation. Reverse these directions in
468               the improbable event that the display's native subpixel order is
469               `bgr`.
470             '';
471           };
473           lcdfilter = lib.mkOption {
474             default = "default";
475             type = lib.types.enum [
476               "none"
477               "default"
478               "light"
479               "legacy"
480             ];
481             description = ''
482               FreeType LCD filter. At high resolution (> 200 DPI), LCD filtering
483               has no visible effect; users of such displays may want to select
484               `none`.
485             '';
486           };
488         };
490         cache32Bit = lib.mkOption {
491           default = false;
492           type = lib.types.bool;
493           description = ''
494             Generate system fonts cache for 32-bit applications.
495           '';
496         };
498         allowBitmaps = lib.mkOption {
499           type = lib.types.bool;
500           default = true;
501           description = ''
502             Allow bitmap fonts. Set to `false` to ban all
503             bitmap fonts.
504           '';
505         };
507         allowType1 = lib.mkOption {
508           type = lib.types.bool;
509           default = false;
510           description = ''
511             Allow Type-1 fonts. Default is `false` because of
512             poor rendering.
513           '';
514         };
516         useEmbeddedBitmaps = lib.mkOption {
517           type = lib.types.bool;
518           default = false;
519           description = "Use embedded bitmaps in fonts like Calibri.";
520         };
522       };
524     };
526   };
527   config = lib.mkMerge [
528     (lib.mkIf cfg.enable {
529       environment.systemPackages = [ pkgs.fontconfig ];
530       environment.etc.fonts.source = "${fontconfigEtc}/etc/fonts/";
531       security.apparmor.includes."abstractions/fonts" = ''
532         # fonts.conf
533         r ${pkg.out}/etc/fonts/fonts.conf,
535         # fontconfig default config files
536         r ${pkg.out}/etc/fonts/conf.d/*.conf,
538         # 00-nixos-cache.conf
539         r ${cacheConf},
541         # 10-nixos-rendering.conf
542         r ${renderConf},
544         # 50-user.conf
545         ${lib.optionalString cfg.includeUserConf ''
546           r ${pkg.out}/etc/fonts/conf.d.bak/50-user.conf,
547         ''}
549         # local.conf (indirect priority 51)
550         ${lib.optionalString (cfg.localConf != "") ''
551           r ${localConf},
552         ''}
554         # 52-nixos-default-fonts.conf
555         r ${defaultFontsConf},
557         # 53-no-bitmaps.conf
558         r ${rejectBitmaps},
560         ${lib.optionalString (!cfg.allowType1) ''
561           # 53-nixos-reject-type1.conf
562           r ${rejectType1},
563         ''}
564       '';
565     })
566     (lib.mkIf cfg.enable {
567       fonts.fontconfig.confPackages = [ confPkg ];
568     })
569   ];