zng/font.rs
1//! Fonts service and text shaping.
2//!
3//! The most common types in this module are used through the [`Text!`] widget properties related to font configuration.
4//!
5//! ```
6//! use zng::{prelude::*, font::FontName};
7//!
8//! # let _scope = APP.defaults();
9//! # let _ =
10//! Text! {
11//! txt = "hello";
12//! font_family = FontName::monospace();
13//! }
14//! # ;
15//! ```
16//!
17//! Internally the [`Text!`] widget implements text segmenting and shaping using the types provided by this module,
18//! but you only need to interact with these types directly if you are authoring new text properties or a new custom
19//! text rendering widget.
20//!
21//! The second most common type used is the [`FONTS`] service. The service can be used to register custom fonts, query system fonts and
22//! manage the font cache.
23//!
24//! # Fonts Service
25//!
26//! The example below demonstrates a font query and custom embedded font installation.
27//!
28//! ```
29//! # macro_rules! include_bytes { ($tt:tt) => { &[] } }
30//! # use zng::{prelude::*, font::*, l10n::*};
31//! # fn main() { }
32//! /// set custom fallback font for the ⌫ symbol.
33//! async fn set_fallback_font() {
34//! use zng::font::*;
35//! let und = lang!(und);
36//!
37//! let shaped_icon = FONTS
38//! .list(
39//! &FontNames::system_ui(&und),
40//! FontStyle::Normal,
41//! FontWeight::NORMAL,
42//! FontStretch::NORMAL,
43//! &und,
44//! )
45//! .wait_rsp()
46//! .await
47//! .sized(layout::Px(11), vec![])
48//! .shape_text(&SegmentedText::new("⌫", layout::LayoutDirection::LTR), &TextShapingArgs::default());
49//!
50//! if shaped_icon.is_empty() || shaped_icon.glyphs().flat_map(|g| g.1).any(|g| g.index == 0) {
51//! // OS UI and fallback fonts do not support `⌫`, load custom font that does.
52//!
53//! static FALLBACK: &[u8] = include_bytes!("res/calculator/notosanssymbols2-regular-subset.ttf");
54//! let fallback = CustomFont::from_bytes("fallback", FontDataRef::from_static(FALLBACK), 0);
55//!
56//! FONTS.register(fallback).wait_rsp().await.unwrap();
57//! FONTS.generics().set_fallback(und, "fallback");
58//! }
59//! }
60//! ```
61//!
62//! This code is taken from the `examples/calculator.rs` example,
63//! it uses [`FONTS.list`](FONTS::list) to get the font [`system_ui`](FontNames::system_ui) fonts that are used by default. The code
64//! then checks if any of system fonts has a glyph for the `⌫` character, if none of the fonts support it a [`CustomFont`] is
65//! loaded from an embedded font and installed using [`FONTS.register`](FONTS::register). Finally the [`FONTS.generics`](FONTS::generics)
66//! is used to override the fallback font.
67//!
68//! The `FONTS.generics` can also be used to change what font is used for the specially named fonts like [`FontName::sans_serif`].
69//!
70//! # Text Segmenting and Shaping
71//!
72//! The most advance feature provided by this module is text segmenting and shaping. Text segmenting is the process of analyzing
73//! raw text and splitting it into distinct segments that define things like the layout direction of text runs, words and spaces,
74//! points where text can be inserted and where wrap line-breaks can happen, this is defined the type [`SegmentedText`].
75//! A segmented text can then be shaped, that is actual glyphs resolved for each segment and positioned according to available space,
76//! this is defined by the [`ShapedText`] type.
77//!
78//! The example below segments and shapes a text, generating a markdown report from some of the data computed.
79//!
80//! ```
81//! # fn main() { }
82//! use std::fmt::Write as _;
83//! use zng::{font::*, l10n::Lang, prelude_wgt::Px, text::*, var::Var};
84//!
85//! async fn report_segment_and_glyphs(txt: &str, lang: &Lang) -> Txt {
86//! let mut report = formatx!("# Shape & Segment\n\n{txt}\n\n");
87//!
88//! // start font query in parallel
89//! let font_face = FONTS.list(
90//! &FontNames::system_ui(lang),
91//! FontStyle::Normal,
92//! FontWeight::NORMAL,
93//! FontStretch::NORMAL,
94//! lang,
95//! );
96//!
97//! // segment text
98//! let segmented_txt = SegmentedText::new(Txt::from_str(txt), lang.direction());
99//!
100//! write!(&mut report, "### Segments\n\n|text|kind|\n|--|--|\n").unwrap();
101//! for (txt, seg) in segmented_txt.iter() {
102//! writeln!(&mut report, "|{txt:?}|{:?}|", seg.kind).unwrap();
103//! }
104//!
105//! // wait font query
106//! let font = font_face.wait_into_rsp().await;
107//! // gets the best font for the size
108//! let font = font.sized(Px(20), vec![]);
109//!
110//! write!(&mut report, "### Fonts\n\n").unwrap();
111//! let mut sep = "";
112//! for f in font.iter() {
113//! write!(&mut report, "{sep}{}", f.face().family_name()).unwrap();
114//! sep = ", ";
115//! }
116//! writeln!(&mut report, "\n").unwrap();
117//!
118//! // shape text
119//! let shaped_txt = font.shape_text(
120//! &segmented_txt,
121//! &TextShapingArgs {
122//! lang: lang.clone(),
123//! direction: segmented_txt.base_direction(),
124//! line_height: font.best().metrics().line_height(),
125//! ..TextShapingArgs::default()
126//! },
127//! );
128//!
129//! write!(&mut report, "### Glyphs\n\n|text|glyphs|\n|--|--|\n").unwrap();
130//! for line in shaped_txt.lines() {
131//! for seg in line.segs() {
132//! let txt = seg.text(txt);
133//! write!(&mut report, "|{txt:?}|").unwrap();
134//! let mut sep = "";
135//! for (font, glyphs) in seg.glyphs() {
136//! write!(&mut report, "{sep}**{}** ", font.face().family_name(),).unwrap();
137//! sep = " | ";
138//!
139//! let mut sep = "";
140//! for g in glyphs {
141//! write!(&mut report, "{sep}{}", g.index).unwrap();
142//! sep = ", ";
143//! }
144//! }
145//! writeln!(&mut report).unwrap();
146//! }
147//! }
148//!
149//! report
150//! }
151//! ```
152//!
153//! Note that you can access the segmented and shaped text of a [`Text!`] widget using the [`TEXT`] service.
154//!
155//! [`Text!`]: struct@crate::text::Text
156//! [`TEXT`]: struct@crate::text::TEXT
157//!
158//! # Full API
159//!
160//! See [`zng_ext_font`] for the full font and shaping API.
161
162pub use zng_ext_font::{
163 BidiLevel, CaretIndex, ColorGlyph, ColorGlyphs, ColorPalette, ColorPaletteType, ColorPalettes, CustomFont, FONT_CHANGED_EVENT, FONTS,
164 Font, FontChange, FontChangedArgs, FontColorPalette, FontDataRef, FontFace, FontFaceList, FontFaceMetrics, FontList, FontMetrics,
165 FontName, FontNames, FontSize, FontStretch, FontStyle, FontWeight, HYPHENATION, HyphenationDataDir, HyphenationDataSource, Hyphens,
166 Justify, LayoutDirections, LetterSpacing, LineBreak, LineHeight, LineSpacing, OutlineSink, ParagraphSpacing, SegmentedText,
167 SegmentedTextIter, ShapedColoredGlyphs, ShapedLine, ShapedSegment, ShapedText, TabLength, TextLineThickness, TextOverflowInfo,
168 TextSegment, TextSegmentKind, TextShapingArgs, TextTransformFn, UnderlineThickness, WhiteSpace, WordBreak, WordSpacing, font_features,
169 unicode_bidi_levels, unicode_bidi_sort,
170};