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