R/reconfigure-font.R

Defines functions reconfigure_font

Documented in reconfigure_font

#' Create an complete, alternate font family with the same customized features
#'
#' @param family font family name
#' @param width font width (defaults to "normal")
#' @param ligatures,letters,numbers See [systemfonts::font_feature()]
#' @param prefix string to use as a prefix to the names of the newly generated font family.
#'        If not specified, a guaranteed unique identifier will be used.
#' @param ... Extra four-letter font feature flags passed on to [systemfonts::font_feature()]. See
#'        See [Microsoft](https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist) and
#'        [Wikipedia](https://en.wikipedia.org/wiki/List_of_typographic_features) for tag descriptions.
#' @return list with names of all the customized font family members. A `family`
#'         attribute is included which is the name of the family this variant is
#'         based on.
#' @export
#' @examples
#' reconfigure_font(
#'   family = "Inter",
#'   width = "normal",
#'   ligatures = "discretionary",
#'   calt = 1, tnum = 1, case = 1,
#'   dlig = 1, ss01 = 1, kern = 1,
#'   zero = 0, salt = 0
#' ) -> inter_1
reconfigure_font <- function(family, width = "normal",
                             ligatures = NULL, letters = NULL, numbers = NULL,
                             prefix = uuid::UUIDgenerate(), ...) {

  # make sure the font exists

  fam <- systemfonts::system_fonts()
  fam <- fam[tolower(fam$family) == tolower(family) & fam$width == width,]

  if (nrow(fam) == 0) stop("No font family found with the specified name and width.", call. = FALSE)

  # order by weight

  fam <- fam[order(fam$weight),]

  # make sure the font supports all the features specified

  supports <- unlist(textshaping::get_font_features(family))
  supplied <- list(...)
  supplied <- setdiff(names(supplied), c("ligatures", "letters", "numbers"))
  unsupported <- supplied[!(supplied %in% supports)]

  if (length(unsupported) != 0) {
    stop(
      sprintf(
        "%s does not support (%s) feature%s but does support (%s).",
        family,
        paste0(unsupported, collapse = ", "),
        if (length(unsupported == 1)) "" else "s",
        paste0(supports, collapse = ", ")
      ),
      call. = FALSE

    )
  }

  # set the features we'll use with each variant

  font_feature(
    ligatures = ligatures,
    letters = letters,
    numbers = numbers,
    ...
  ) -> feat

  # make some room for the return value

  ret <- list()

  # go through each default variant and make a new font with
  # the specified feature(s) configuration

  for (idx in 1:nrow(fam)) {

    tmp_nam <- sprintf("%s %s %s", prefix, family, fam$style[idx])

    idx_nam <- as.character(fam$weight[idx])
    if (fam$italic[idx]) idx_nam <- sprintf("%s_italic", idx_nam)
    if (fam$monospace[idx]) idx_nam <- sprintf("%s_mono", idx_nam)
    if (fam$style[idx] == "Light") idx_nam <- sprintf("%s_light", idx_nam)

    (ret[[idx_nam]] <- tmp_nam)

    register_variant(
      name = tmp_nam,
      weight = as.character(fam$weight[idx]),
      features = feat,
      family = family,
      width = width
    )

  }

  # keep the font name handy
  attr(ret, "family") <- family

  ret

}
hrbrmstr/hrbragg documentation built on Feb. 3, 2022, 1:39 a.m.