--- title: "Font Management in ksTFL" author: "ksTFL Development Team" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true toc_depth: 3 css: ksTFL-vignette.css vignette: > %\VignetteIndexEntry{Font Management in ksTFL} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Overview ksTFL renders DOCX documents using a C++ engine that requires TrueType/OpenType font files for text measurement and pagination. Starting with version 0.7.0, the package **automatically discovers fonts installed on the operating system** at load time. If a required font is not available on the system, a metrically compatible open-source fallback is used. This guide explains how font discovery works, which fallback fonts are bundled, and how to configure custom font directories. ## How Font Discovery Works When ksTFL is loaded, it performs four steps: 1. **Scan system directories.** The C++ font scanner inspects platform-specific directories and reads family names and style flags from `.ttf`, `.otf`, and `.ttc` files. 2. **Scan user directories.** If the R option `ksTFL.font_dirs` is set, those directories are scanned as well. 3. **Scan bundled fallbacks.** The package's own `inst/fonts/` directory is scanned last. 4. **Resolve target fonts.** For each target family (Arial, Times New Roman, Courier New, Georgia, Verdana, Trebuchet MS), ksTFL keeps the discovered font when available or assigns a designated fallback. **Key rule:** system-installed fonts always take priority. The bundled fallbacks are only used when a target font is not found anywhere on the system. ### Platform-Specific Directories The scanner inspects the following directories by default: | Platform | Directories | | ----------- | -------------------------------------------------------------------------------------------------------- | | **Linux** | `/usr/share/fonts`, `/usr/local/share/fonts`, `~/.local/share/fonts`, `~/.fonts`, plus any XDG data dirs | | **macOS** | `/System/Library/Fonts`, `/Library/Fonts`, `~/Library/Fonts` | | **Windows** | System fonts directory (from registry), plus user fonts in `%LOCALAPPDATA%\Microsoft\Windows\Fonts` | ## Target Fonts and Fallbacks The rendering engine targets six font families commonly used in clinical documents. Each has a metrically compatible open-source fallback bundled with the package: | Target Font | Fallback Font | Notes | | ------------------- | ---------------- | --------------------------------------- | | **Arial** | Liberation Sans | Metrically identical to Arial | | **Times New Roman** | Liberation Serif | Metrically identical to Times New Roman | | **Courier New** | Liberation Mono | Metrically identical to Courier New | | **Georgia** | Liberation Serif | Serif fallback for Georgia | | **Verdana** | Liberation Sans | Sans-serif fallback for Verdana | | **Trebuchet MS** | Liberation Sans | Sans-serif fallback for Trebuchet MS | All bundled fonts are licensed under the SIL Open Font License 1.1. If a font family requested in a spec (via `s_font(font_name = "...")`) is not a target font and is not found on the system, the engine falls back to Liberation Sans as the last resort. For convenience, ksTFL also ships built-in style atoms for the target font families: `font_arial`, `font_courier_new`, `font_times_new_roman`, `font_georgia`, `font_verdana`, and `font_trebuchet_ms`. These atoms set only `font_name`, so they can be safely combined with size, colour, alignment, and other style atoms via `f_combine()`. ## Checking Font Status After loading the package, call `tfl_font_status()` to see the current font resolution: ```r library(ksTFL) tfl_font_status() #> ksTFL font scan: 3 target(s) resolved, 3 using fallback #> [ok] Arial -> Arial #> [ok] Times New Roman -> Times New Roman #> [ok] Courier New -> Courier New #> [fallback] Georgia -> Liberation Serif #> [fallback] Verdana -> Liberation Sans #> [fallback] Trebuchet MS -> Liberation Sans #> Scanned 5 directories ``` **Reading the output:** - **`[ok]`** — The target font was found on the system and will be used directly. - **`[fallback]`** — The target font was not found; the bundled fallback is used instead. ## Adding Custom Font Directories If proprietary fonts are installed in a non-standard location (e.g., a network share or a project-local folder), point the `ksTFL.font_dirs` option to those directories **before** loading the package, or rescan afterwards: ### Option A: Set before loading ```r options(ksTFL.font_dirs = c("/opt/company-fonts", "/mnt/shared/fonts")) library(ksTFL) ``` ### Option B: Set and rescan after loading ```r library(ksTFL) options(ksTFL.font_dirs = "/opt/company-fonts") tfl_rescan_fonts() ``` Both approaches produce the same result. The `ksTFL.font_dirs` option accepts a character vector of directory paths. ## Rescanning Fonts Call `tfl_rescan_fonts()` after: - Installing new system fonts - Changing the `ksTFL.font_dirs` option - Mounting a new network font directory ```r # Install Georgia to /usr/local/share/fonts/georgia/ ... then: tfl_rescan_fonts() #> ksTFL font scan: 6 target(s) resolved, 0 using fallback #> [ok] Arial -> Arial #> [ok] Times New Roman -> Times New Roman #> [ok] Courier New -> Courier New #> [ok] Georgia -> Georgia #> [ok] Verdana -> Verdana #> [ok] Trebuchet MS -> Trebuchet MS #> Scanned 5 directories ``` ## Startup Messages When the package is attached, it prints a concise summary if any target fonts are using fallbacks: ``` ksTFL v0.7.0 - Clinical TFL Framework For help, type: ??ksTFL Note: 3 font(s) using fallback: Georgia, Verdana, Trebuchet MS Run tfl_font_status() for details. ``` If all target fonts are found on the system, no font-related message is shown. ## Interaction with `write_doc()` The `write_doc()` function (and `replay_report()`) automatically uses the font directories from the scanner cache. You can still pass additional per-call directories via the `font_dirs` argument: ```r write_doc(report, name = "output", outDir = "results", metaPath = tempdir(), font_dirs = "/path/to/extra-fonts") ``` Per-call directories are appended to the scanner's cached list for that render only — they do not modify the global font registry. ## FAQ ### Q: I see `[fallback]` for a font I know is installed. What's wrong? The font may be installed in a directory not scanned by default. Add its directory to `ksTFL.font_dirs` and rescan: ```r options(ksTFL.font_dirs = "/path/to/font/directory") tfl_rescan_fonts() ``` ### Q: Can I use custom fonts not in the target list? Yes. Any font found during scanning is available to the renderer. Use the family name as it appears in the font's metadata (e.g., `s_font(font_name = "Fira Sans")`). If the font is in a non-standard directory, add that directory to `ksTFL.font_dirs`. ### Q: Will documents look different on systems without the proprietary fonts? The fallback fonts (Liberation family) are designed to be metrically compatible with their proprietary counterparts. Line breaks, page breaks, and column widths should be identical or very close. Minor glyph-level differences may exist, but document layout is preserved. ### Q: How do I suppress the startup font warning? You can suppress all startup messages with: ```r suppressPackageStartupMessages(library(ksTFL)) ``` Or install the missing fonts and the message will not appear.