3   NixOS support 2 fontconfig versions, "support" and "latest".
 
   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/
 
  10   This module generates a package containing configuration files and link it in /etc/fonts.
 
  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.
 
  17 { config, pkgs, lib, ... }:
 
  22   cfg = config.fonts.fontconfig;
 
  24   fcBool = x: "<bool>" + (boolToString x) + "</bool>";
 
  26   # back-supported fontconfig version and package
 
  27   # version is used for font cache generation
 
  28   supportVersion = "210";
 
  29   supportPkg = pkgs."fontconfig_${supportVersion}";
 
  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;
 
  37   # supported version fonts.conf
 
  38   supportFontsConf = pkgs.makeFontsConf { fontconfig = supportPkg; fontDirectories = config.fonts.fonts; };
 
  40   # configuration file to read fontconfig cache
 
  43   cacheConfSupport = makeCacheConf { version = supportVersion; };
 
  44   cacheConfLatest = makeCacheConf { };
 
  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
 
  51   makeCacheConf = { version ? null }:
 
  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};
 
  61     pkgs.writeText "fc-00-nixos-cache.conf" ''
 
  63       <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
 
  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>
 
  77   # rendering settings configuration file
 
  79   renderConf = pkgs.writeText "fc-10-nixos-rendering.conf" ''
 
  81     <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
 
  84       <!-- Default rendering settings -->
 
  85       <match target="pattern">
 
  86         <edit mode="append" name="hinting">
 
  87           ${fcBool cfg.hinting.enable}
 
  89         <edit mode="append" name="autohint">
 
  90           ${fcBool cfg.hinting.autohint}
 
  92         <edit mode="append" name="hintstyle">
 
  93           <const>hintslight</const>
 
  95         <edit mode="append" name="antialias">
 
  96           ${fcBool cfg.antialias}
 
  98         <edit mode="append" name="rgba">
 
  99           <const>${cfg.subpixel.rgba}</const>
 
 101         <edit mode="append" name="lcdfilter">
 
 102           <const>lcd${cfg.subpixel.lcdfilter}</const>
 
 106       ${optionalString (cfg.dpi != 0) ''
 
 107       <match target="pattern">
 
 108         <edit name="dpi" mode="assign">
 
 109           <double>${toString cfg.dpi}</double>
 
 117   # local configuration file
 
 118   localConf = pkgs.writeText "fc-local.conf" cfg.localConf;
 
 120   # default fonts configuration file
 
 124       genDefault = fonts: name:
 
 125         optionalString (fonts != [ ]) ''
 
 126           <alias binding="same">
 
 127             <family>${name}</family>
 
 129             ${concatStringsSep ""
 
 131               <family>${font}</family>
 
 137     pkgs.writeText "fc-52-nixos-default-fonts.conf" ''
 
 138       <?xml version='1.0'?>
 
 139       <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
 
 142         <!-- Default fonts -->
 
 143         ${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
 
 145         ${genDefault cfg.defaultFonts.serif     "serif"}
 
 147         ${genDefault cfg.defaultFonts.monospace "monospace"}
 
 149         ${genDefault cfg.defaultFonts.emoji "emoji"}
 
 154   # bitmap font options
 
 156   rejectBitmaps = pkgs.writeText "fc-53-no-bitmaps.conf" ''
 
 157     <?xml version="1.0"?>
 
 158     <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
 
 161     ${optionalString (!cfg.allowBitmaps) ''
 
 162     <!-- Reject bitmap fonts -->
 
 166           <patelt name="scalable"><bool>false</bool></patelt>
 
 172     <!-- Use embedded bitmaps in fonts like Calibri? -->
 
 173     <match target="font">
 
 174       <edit name="embeddedbitmap" mode="assign">
 
 175         ${fcBool cfg.useEmbeddedBitmaps}
 
 182   # reject Type 1 fonts
 
 184   rejectType1 = pkgs.writeText "fc-53-nixos-reject-type1.conf" ''
 
 185     <?xml version="1.0"?>
 
 186     <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
 
 189     <!-- Reject Type 1 fonts -->
 
 193           <patelt name="fontformat"><string>Type 1</string></patelt>
 
 201   # fontconfig configuration package
 
 202   confPkg = pkgs.runCommand "fontconfig-conf"
 
 204       preferLocalBuild = true;
 
 206     support_folder=$out/etc/fonts/conf.d
 
 207     latest_folder=$out/etc/fonts/${latestVersion}/conf.d
 
 209     mkdir -p $support_folder
 
 210     mkdir -p $latest_folder
 
 213     ln -s ${supportFontsConf} $support_folder/../fonts.conf
 
 214     ln -s ${latestPkg.out}/etc/fonts/fonts.conf \
 
 215           $latest_folder/../fonts.conf
 
 217     # fontconfig default config files
 
 218     ln -s ${supportPkg.out}/etc/fonts/conf.d/*.conf \
 
 220     ln -s ${latestPkg.out}/etc/fonts/conf.d/*.conf \
 
 223     # update latest 51-local.conf path to look at the latest local.conf
 
 224     rm    $latest_folder/51-local.conf
 
 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
 
 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
 
 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
 
 240     ${optionalString (!cfg.includeUserConf) ''
 
 241     rm $support_folder/50-user.conf
 
 242     rm $latest_folder/50-user.conf
 
 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
 
 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
 
 256     ln -s ${rejectBitmaps} $support_folder/53-no-bitmaps.conf
 
 257     ln -s ${rejectBitmaps} $latest_folder/53-no-bitmaps.conf
 
 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
 
 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;
 
 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.
 
 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.
 
 310         confPackages = mkOption {
 
 312           type = with types; listOf path;
 
 315             Fontconfig configuration packages.
 
 319         antialias = mkOption {
 
 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.
 
 333             Force DPI setting. Setting to <literal>0</literal> disables DPI
 
 334             forcing; the DPI detected for the display will be used.
 
 338         localConf = mkOption {
 
 342             System-wide customization file contents, has higher priority than
 
 343             <literal>defaultFonts</literal> settings.
 
 348           monospace = mkOption {
 
 349             type = types.listOf types.str;
 
 350             default = [ "DejaVu Sans Mono" ];
 
 352               System-wide default monospace font(s). Multiple fonts may be
 
 353               listed in case multiple languages must be supported.
 
 357           sansSerif = mkOption {
 
 358             type = types.listOf types.str;
 
 359             default = [ "DejaVu Sans" ];
 
 361               System-wide default sans serif font(s). Multiple fonts may be
 
 362               listed in case multiple languages must be supported.
 
 367             type = types.listOf types.str;
 
 368             default = [ "DejaVu Serif" ];
 
 370               System-wide default serif font(s). Multiple fonts may be listed
 
 371               in case multiple languages must be supported.
 
 376             type = types.listOf types.str;
 
 377             default = [ "Noto Color Emoji" ];
 
 379               System-wide default emoji font(s). Multiple fonts may be listed
 
 380               in case a font does not support all emoji.
 
 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.
 
 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.
 
 403           autohint = mkOption {
 
 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.
 
 414         includeUserConf = mkOption {
 
 418             Include the user configuration from
 
 419             <filename>~/.config/fontconfig/fonts.conf</filename> or
 
 420             <filename>~/.config/fontconfig/conf.d</filename>.
 
 428             type = types.enum [ "rgb" "bgr" "vrgb" "vbgr" "none" ];
 
 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>.
 
 442           lcdfilter = mkOption {
 
 444             type = types.enum [ "none" "default" "light" "legacy" ];
 
 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>.
 
 454         cache32Bit = mkOption {
 
 458             Generate system fonts cache for 32-bit applications.
 
 462         allowBitmaps = mkOption {
 
 466             Allow bitmap fonts. Set to <literal>false</literal> to ban all
 
 471         allowType1 = mkOption {
 
 475             Allow Type-1 fonts. Default is <literal>false</literal> because of
 
 480         useEmbeddedBitmaps = mkOption {
 
 483           description = ''Use embedded bitmaps in fonts like Calibri.'';
 
 493       environment.systemPackages = [ pkgs.fontconfig ];
 
 494       environment.etc.fonts.source = "${fontconfigEtc}/etc/fonts/";
 
 495       security.apparmor.includes."abstractions/fonts" = ''
 
 497         r ${supportFontsConf}
 
 498         r ${latestPkg.out}/etc/fonts/fonts.conf
 
 500         # fontconfig default config files
 
 501         r ${supportPkg.out}/etc/fonts/conf.d/*.conf,
 
 502         r ${latestPkg.out}/etc/fonts/conf.d/*.conf,
 
 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
 
 508         # 00-nixos-cache.conf
 
 509         r ${cacheConfSupport},
 
 510         r ${cacheConfLatest},
 
 512         # 10-nixos-rendering.conf
 
 515         # local.conf (indirect priority 51)
 
 516         ${optionalString (cfg.localConf != "") ''
 
 520         # 52-nixos-default-fonts.conf
 
 521         r ${defaultFontsConf},
 
 526         ${optionalString (!cfg.allowType1) ''
 
 527         # 53-nixos-reject-type1.conf
 
 532     (mkIf (cfg.enable && !cfg.penultimate.enable) {
 
 533       fonts.fontconfig.confPackages = [ confPkg ];