blob: 9f1bd6372ae71e30e0b1270af2eac02623bbd691 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::serde_ext::*,
char_collection::CharCollection,
fidl_fuchsia_fonts::{GenericFontFamily, Slant, Width, WEIGHT_NORMAL},
fuchsia_url::pkg_url::PkgUrl,
offset_string::OffsetString,
serde::{
de::{Deserialize, Deserializer, Error},
ser::{Serialize, Serializer},
},
serde_derive::{Deserialize, Serialize},
std::{convert::TryFrom, path::PathBuf},
};
/// Version 2 of the Font Manifest schema.
///
/// Less duplication than v1 schema. Intended for generation using a Rust tool, not for writing by
/// hand.
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct FontsManifest {
/// List of families in the manifest.
pub families: Vec<Family>,
}
/// Represents a font family, its metadata, and its font files.
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct Family {
pub name: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub aliases: Vec<String>,
/// The generic font family that this font belongs to. If this is a specialty font (e.g. for
/// custom icons), this should be set to `None`.
#[serde(with = "OptGenericFontFamily")]
pub generic_family: Option<GenericFontFamily>,
/// Whether this family can be used as a fallback for other fonts (within the same generic
/// family, or as a last resort).
pub fallback: bool,
/// Collection of font files that make up the font family.
pub assets: Vec<Asset>,
}
/// Represents a single font file, which contains one or more [`Typeface`]s.
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct Asset {
/// Asset identifier. Should be a valid file name, e.g. `"Roboto-Regular.ttf`.
pub file_name: String,
/// Where to find the file
pub location: AssetLocation,
/// List of typefaces in the file
pub typefaces: Vec<Typeface>,
}
impl Asset {
/// If the asset represents a local file, returns the package-relative path to the file.
/// Otherwise, returns `None`.
pub fn local_path(&self) -> Option<PathBuf> {
match &self.location {
AssetLocation::LocalFile(locator) => {
Some(locator.directory.join(self.file_name.clone()))
}
_ => None,
}
}
}
/// Describes the location of a font asset.
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub enum AssetLocation {
/// Indicates that the file is accessible through a file path in the font server's namespace
/// (e.g. at `/config/data/fonts/`).
#[serde(rename = "local")]
LocalFile(LocalFileLocator),
/// Indicates that the file is accessible in a separate font package (e.g.
/// `fuchsia-pkg://fuchsia.com/font-package-roboto-regular-ttf`).
#[serde(rename = "package")]
Package(PackageLocator),
}
/// Describes the location of a local file asset. Used in conjunction with [`Asset::file_name`].
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct LocalFileLocator {
/// Package-relative path to the file, excluding the file name
pub directory: PathBuf,
}
/// Describes the location of a font asset that's part of a Fuchsia package. Used in conjunction
/// with [`Asset::file_name`].
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct PackageLocator {
/// URL of just the package (not including the file name)
pub package: PkgUrl,
/// Type of package
pub package_set: PackageSet,
}
/// Describes which set of dependencies a font package belongs to.
///
/// See https://fuchsia.dev/fuchsia-src/development/build/boards_and_products#dependency_sets.
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum PackageSet {
/// Package is in the device's base image (the "base set" of packages)
Base,
/// Package is available ephemerally (the "universe set" of packages)
Universe,
}
/// Describes a single typeface within a font file
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct Typeface {
/// Index of the typeface in the file. If the file only contains a single typeface, this will
/// always be `0`.
#[serde(default = "Typeface::default_index")]
pub index: u32,
/// List of languages that the typeface supports, in BCP-47 format.
///
/// Example: `["en", "zh-Hant", "sr-Cyrl"]`
#[serde(default = "Typeface::default_languages", skip_serializing_if = "Vec::is_empty")]
pub languages: Vec<String>,
/// Text style of the typeface.
#[serde(flatten)]
pub style: Style,
/// List of Unicode code points supported by the typeface.
#[serde(with = "code_points_serde")]
pub code_points: CharCollection,
}
impl Typeface {
fn default_index() -> u32 {
0
}
fn default_languages() -> Vec<String> {
vec![]
}
}
/// Used for de/serializing a `CharCollection`.
mod code_points_serde {
use super::*;
pub fn deserialize<'d, D>(deserializer: D) -> Result<CharCollection, D::Error>
where
D: Deserializer<'d>,
{
let offset_string = OffsetString::deserialize(deserializer)?;
CharCollection::try_from(offset_string).map_err(|e| D::Error::custom(format!("{:?}", e)))
}
pub fn serialize<S>(code_points: &CharCollection, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let offset_string: OffsetString = code_points.into();
offset_string.serialize(serializer)
}
}
/// Describes a typeface's style properties. Equivalent to [`fidl_fuchsia_fonts::Style2`], but all
/// fields are required.
#[derive(Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct Style {
#[serde(default = "Style::default_slant", with = "SlantDef")]
pub slant: Slant,
#[serde(default = "Style::default_weight")]
pub weight: u16,
#[serde(default = "Style::default_width", with = "WidthDef")]
pub width: Width,
}
impl Style {
fn default_slant() -> Slant {
Slant::Upright
}
fn default_weight() -> u16 {
WEIGHT_NORMAL
}
fn default_width() -> Width {
Width::Normal
}
}