summaryrefslogtreecommitdiff
path: root/src/library/font.rs
blob: ae059512678800874ee057c2da3334238875a7af (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use fontdock::{FontStyle, FontWeight, FontWidth};

use crate::length::ScaleLength;
use super::*;

/// `font`: Configure the font.
///
/// # Positional arguments
/// - The font size (optional, length or relative to previous font size).
/// - A font family fallback list (optional, identifiers or strings).
///
/// # Keyword arguments
/// - `style`: `normal`, `italic` or `oblique`.
/// - `weight`: `100` - `900` or a name like `thin`.
/// - `width`: `1` - `9` or a name like `condensed`.
/// - Any other keyword argument whose value is a table of strings is a class
///   fallback definition like:
///   ```typst
///   serif = ("Source Serif Pro", "Noto Serif")
///   ```
pub async fn font(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
    let mut f = Feedback::new();
    let mut text = ctx.style.text.clone();
    let mut updated_fallback = false;

    let content = args.take::<SyntaxTree>();

    if let Some(s) = args.take::<ScaleLength>() {
        match s {
            ScaleLength::Absolute(length) => {
                text.base_font_size = length.as_raw();
                text.font_scale = 1.0;
            }
            ScaleLength::Scaled(scale) => text.font_scale = scale,
        }
    }

    let list: Vec<_> = args.take_all_num_vals::<StringLike>()
        .map(|s| s.to_lowercase())
        .collect();

    if !list.is_empty() {
        *text.fallback.list_mut() = list;
        updated_fallback = true;
    }

    if let Some(style) = args.take_key::<FontStyle>("style", &mut f) {
        text.variant.style = style;
    }

    if let Some(weight) = args.take_key::<FontWeight>("weight", &mut f) {
        text.variant.weight = weight;
    }

    if let Some(width) = args.take_key::<FontWidth>("width", &mut f) {
        text.variant.width = width;
    }

    for (class, mut table) in args.take_all_str::<TableValue>() {
        let fallback = table.take_all_num_vals::<StringLike>()
            .map(|s| s.to_lowercase())
            .collect();

        text.fallback.set_class_list(class, fallback);
        updated_fallback = true;
    }

    if updated_fallback {
        text.fallback.flatten();
    }

    let commands = match content {
        Some(tree) => vec![
            SetTextStyle(text),
            LayoutSyntaxTree(tree),
            SetTextStyle(ctx.style.text.clone()),
        ],
        None => vec![SetTextStyle(text)],
    };

    args.unexpected(&mut f);
    Pass::commands(commands, f)
}