mirror of
https://github.com/typst/typst
synced 2025-05-15 17:45:27 +08:00
Tidying
This commit is contained in:
parent
14048937b8
commit
8a38899c98
@ -7,7 +7,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::syntax::{Span, Spanned};
|
use crate::syntax::{Span, Spanned};
|
||||||
|
|
||||||
/// Early-return with a vec-boxed [`Error`].
|
/// Early-return with a vec-boxed [`Error`].
|
||||||
#[macro_export]
|
|
||||||
macro_rules! bail {
|
macro_rules! bail {
|
||||||
($span:expr, $message:expr $(,)?) => {
|
($span:expr, $message:expr $(,)?) => {
|
||||||
return Err($crate::diag::Error::boxed($span, $message,))
|
return Err($crate::diag::Error::boxed($span, $message,))
|
||||||
|
@ -72,14 +72,6 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether the value is castable into a specific type.
|
|
||||||
pub fn is<T>(&self) -> bool
|
|
||||||
where
|
|
||||||
T: Cast<Value>,
|
|
||||||
{
|
|
||||||
T::is(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to cast the value into a specific type.
|
/// Try to cast the value into a specific type.
|
||||||
pub fn cast<T>(self) -> StrResult<T>
|
pub fn cast<T>(self) -> StrResult<T>
|
||||||
where
|
where
|
||||||
|
27
src/font.rs
27
src/font.rs
@ -149,31 +149,48 @@ impl FontStore {
|
|||||||
pub fn families(&self) -> impl Iterator<Item = &str> + '_ {
|
pub fn families(&self) -> impl Iterator<Item = &str> + '_ {
|
||||||
// Since the keys are lowercased, we instead use the family field of the
|
// Since the keys are lowercased, we instead use the family field of the
|
||||||
// first face's info.
|
// first face's info.
|
||||||
|
let faces = self.loader.faces();
|
||||||
self.families
|
self.families
|
||||||
.values()
|
.values()
|
||||||
.map(move |id| self.loader.faces()[id[0].0 as usize].family.as_str())
|
.map(move |id| faces[id[0].0 as usize].family.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A font face.
|
/// A font face.
|
||||||
pub struct Face {
|
pub struct Face {
|
||||||
|
/// The raw face data, possibly shared with other faces from the same
|
||||||
|
/// collection. Must stay alive put, because `ttf` points into it using
|
||||||
|
/// unsafe code.
|
||||||
buffer: Rc<Vec<u8>>,
|
buffer: Rc<Vec<u8>>,
|
||||||
|
/// The face's index in the collection (zero if not a collection).
|
||||||
index: u32,
|
index: u32,
|
||||||
|
/// The underlying ttf-parser/rustybuzz face.
|
||||||
ttf: rustybuzz::Face<'static>,
|
ttf: rustybuzz::Face<'static>,
|
||||||
units_per_em: f64,
|
/// How many font units represent one em unit.
|
||||||
|
pub units_per_em: f64,
|
||||||
|
/// The distance from the baseline to the typographic ascender.
|
||||||
pub ascender: Em,
|
pub ascender: Em,
|
||||||
|
/// The approximate height of uppercase letters.
|
||||||
pub cap_height: Em,
|
pub cap_height: Em,
|
||||||
|
/// The approximate height of non-ascending lowercase letters.
|
||||||
pub x_height: Em,
|
pub x_height: Em,
|
||||||
|
/// The distance from the baseline to the typographic descender.
|
||||||
pub descender: Em,
|
pub descender: Em,
|
||||||
|
/// Recommended metrics for a strikethrough line.
|
||||||
pub strikethrough: LineMetrics,
|
pub strikethrough: LineMetrics,
|
||||||
|
/// Recommended metrics for an underline.
|
||||||
pub underline: LineMetrics,
|
pub underline: LineMetrics,
|
||||||
|
/// Recommended metrics for an overline.
|
||||||
pub overline: LineMetrics,
|
pub overline: LineMetrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Metrics for a decorative line.
|
/// Metrics for a decorative line.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct LineMetrics {
|
pub struct LineMetrics {
|
||||||
|
/// The thickness of the line.
|
||||||
pub strength: Em,
|
pub strength: Em,
|
||||||
|
/// The vertical offset of the line from the baseline. Positive goes
|
||||||
|
/// upwards, negative downwards.
|
||||||
pub position: Em,
|
pub position: Em,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +207,6 @@ impl Face {
|
|||||||
unsafe { std::slice::from_raw_parts(buffer.as_ptr(), buffer.len()) };
|
unsafe { std::slice::from_raw_parts(buffer.as_ptr(), buffer.len()) };
|
||||||
|
|
||||||
let ttf = rustybuzz::Face::from_slice(slice, index)?;
|
let ttf = rustybuzz::Face::from_slice(slice, index)?;
|
||||||
|
|
||||||
let units_per_em = f64::from(ttf.units_per_em());
|
let units_per_em = f64::from(ttf.units_per_em());
|
||||||
let to_em = |units| Em::from_units(units, units_per_em);
|
let to_em = |units| Em::from_units(units, units_per_em);
|
||||||
|
|
||||||
@ -252,11 +268,6 @@ impl Face {
|
|||||||
&self.ttf
|
&self.ttf
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of units per em.
|
|
||||||
pub fn units_per_em(&self) -> f64 {
|
|
||||||
self.units_per_em
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert from font units to an em length.
|
/// Convert from font units to an em length.
|
||||||
pub fn to_em(&self, units: impl Into<f64>) -> Em {
|
pub fn to_em(&self, units: impl Into<f64>) -> Em {
|
||||||
Em::from_units(units, self.units_per_em)
|
Em::from_units(units, self.units_per_em)
|
||||||
|
@ -2,11 +2,12 @@ use std::borrow::Cow;
|
|||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use rustybuzz::{Feature, Tag, UnicodeBuffer};
|
use rustybuzz::{Feature, UnicodeBuffer};
|
||||||
|
use ttf_parser::Tag;
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use crate::font::{
|
use crate::font::{
|
||||||
Face, FaceId, FontFamily, FontStretch, FontStyle, FontVariant, FontWeight,
|
Face, FaceId, FontFamily, FontStore, FontStretch, FontStyle, FontVariant, FontWeight,
|
||||||
VerticalFontMetric,
|
VerticalFontMetric,
|
||||||
};
|
};
|
||||||
use crate::geom::{Dir, Em, Length, Point, Size};
|
use crate::geom::{Dir, Em, Length, Point, Size};
|
||||||
@ -19,7 +20,7 @@ use crate::util::SliceExt;
|
|||||||
pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
struct FontDef(Rc<Vec<FontFamily>>);
|
struct FontDef(Rc<Vec<FontFamily>>);
|
||||||
struct FamilyDef(Rc<Vec<String>>);
|
struct FamilyDef(Rc<Vec<String>>);
|
||||||
struct FeatureList(Vec<(String, u32)>);
|
struct FeatureList(Vec<(Tag, u32)>);
|
||||||
struct StylisticSet(Option<u8>);
|
struct StylisticSet(Option<u8>);
|
||||||
|
|
||||||
castable! {
|
castable! {
|
||||||
@ -134,21 +135,23 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
|
|
||||||
castable! {
|
castable! {
|
||||||
FeatureList: "array of strings or dictionary mapping tags to integers",
|
FeatureList: "array of strings or dictionary mapping tags to integers",
|
||||||
Value::Array(values) => Self(values
|
Value::Array(values) => Self(
|
||||||
.into_iter()
|
values
|
||||||
.filter_map(|v| v.cast().ok())
|
.into_iter()
|
||||||
.map(|string: Str| (string.to_lowercase(), 1))
|
.filter_map(|v| v.cast().ok())
|
||||||
.collect()),
|
.map(|string: Str| (Tag::from_bytes_lossy(string.as_bytes()), 1))
|
||||||
Value::Dict(values) => Self(values
|
.collect()
|
||||||
.into_iter()
|
),
|
||||||
.filter_map(|(k, v)| {
|
Value::Dict(values) => Self(
|
||||||
if let Ok(value) = v.cast::<i64>() {
|
values
|
||||||
Some((k.to_lowercase(), value as u32))
|
.into_iter()
|
||||||
} else {
|
.filter_map(|(k, v)| {
|
||||||
None
|
let tag = Tag::from_bytes_lossy(k.as_bytes());
|
||||||
}
|
let num = v.cast::<i64>().ok()?.try_into().ok()?;
|
||||||
})
|
Some((tag, num))
|
||||||
.collect()),
|
})
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = args.named("family")?.or_else(|| {
|
let list = args.named("family")?.or_else(|| {
|
||||||
@ -266,11 +269,10 @@ pub fn shape<'a>(
|
|||||||
let mut glyphs = vec![];
|
let mut glyphs = vec![];
|
||||||
if !text.is_empty() {
|
if !text.is_empty() {
|
||||||
shape_segment(
|
shape_segment(
|
||||||
ctx,
|
ctx.fonts,
|
||||||
&mut glyphs,
|
&mut glyphs,
|
||||||
0,
|
0,
|
||||||
text,
|
text,
|
||||||
style.size,
|
|
||||||
style.variant(),
|
style.variant(),
|
||||||
style.families(),
|
style.families(),
|
||||||
None,
|
None,
|
||||||
@ -452,11 +454,10 @@ enum Side {
|
|||||||
|
|
||||||
/// Shape text with font fallback using the `families` iterator.
|
/// Shape text with font fallback using the `families` iterator.
|
||||||
fn shape_segment<'a>(
|
fn shape_segment<'a>(
|
||||||
ctx: &mut LayoutContext,
|
fonts: &mut FontStore,
|
||||||
glyphs: &mut Vec<ShapedGlyph>,
|
glyphs: &mut Vec<ShapedGlyph>,
|
||||||
base: usize,
|
base: usize,
|
||||||
text: &str,
|
text: &str,
|
||||||
size: Length,
|
|
||||||
variant: FontVariant,
|
variant: FontVariant,
|
||||||
mut families: impl Iterator<Item = &'a str> + Clone,
|
mut families: impl Iterator<Item = &'a str> + Clone,
|
||||||
mut first_face: Option<FaceId>,
|
mut first_face: Option<FaceId>,
|
||||||
@ -468,7 +469,7 @@ fn shape_segment<'a>(
|
|||||||
// Try to load the next available font family.
|
// Try to load the next available font family.
|
||||||
match families.next() {
|
match families.next() {
|
||||||
Some(family) => {
|
Some(family) => {
|
||||||
if let Some(id) = ctx.fonts.select(family, variant) {
|
if let Some(id) = fonts.select(family, variant) {
|
||||||
break (id, true);
|
break (id, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -495,7 +496,7 @@ fn shape_segment<'a>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Shape!
|
// Shape!
|
||||||
let mut face = ctx.fonts.get(face_id);
|
let mut face = fonts.get(face_id);
|
||||||
let buffer = rustybuzz::shape(face.ttf(), tags, buffer);
|
let buffer = rustybuzz::shape(face.ttf(), tags, buffer);
|
||||||
let infos = buffer.glyph_infos();
|
let infos = buffer.glyph_infos();
|
||||||
let pos = buffer.glyph_positions();
|
let pos = buffer.glyph_positions();
|
||||||
@ -545,11 +546,9 @@ fn shape_segment<'a>(
|
|||||||
// Glyphs: E C _ _ A
|
// Glyphs: E C _ _ A
|
||||||
// Clusters: 8 6 4 2 0
|
// Clusters: 8 6 4 2 0
|
||||||
// k=2 i=3
|
// k=2 i=3
|
||||||
|
|
||||||
let ltr = dir.is_positive();
|
let ltr = dir.is_positive();
|
||||||
let first = if ltr { k } else { i };
|
let first = if ltr { k } else { i };
|
||||||
let start = infos[first].cluster as usize;
|
let start = infos[first].cluster as usize;
|
||||||
|
|
||||||
let last = if ltr { i.checked_add(1) } else { k.checked_sub(1) };
|
let last = if ltr { i.checked_add(1) } else { k.checked_sub(1) };
|
||||||
let end = last
|
let end = last
|
||||||
.and_then(|last| infos.get(last))
|
.and_then(|last| infos.get(last))
|
||||||
@ -560,11 +559,10 @@ fn shape_segment<'a>(
|
|||||||
|
|
||||||
// Recursively shape the tofu sequence with the next family.
|
// Recursively shape the tofu sequence with the next family.
|
||||||
shape_segment(
|
shape_segment(
|
||||||
ctx,
|
fonts,
|
||||||
glyphs,
|
glyphs,
|
||||||
base + range.start,
|
base + range.start,
|
||||||
&text[range],
|
&text[range],
|
||||||
size,
|
|
||||||
variant,
|
variant,
|
||||||
families.clone(),
|
families.clone(),
|
||||||
first_face,
|
first_face,
|
||||||
@ -572,7 +570,7 @@ fn shape_segment<'a>(
|
|||||||
tags,
|
tags,
|
||||||
);
|
);
|
||||||
|
|
||||||
face = ctx.fonts.get(face_id);
|
face = fonts.get(face_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
@ -687,12 +685,8 @@ fn tags(features: &FontFeatures) -> Vec<Feature> {
|
|||||||
feat(b"frac", 1);
|
feat(b"frac", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (tag, value) in features.raw.iter() {
|
for &(tag, value) in features.raw.iter() {
|
||||||
tags.push(Feature::new(
|
tags.push(Feature::new(tag, value, ..))
|
||||||
Tag::from_bytes_lossy(tag.as_bytes()),
|
|
||||||
*value,
|
|
||||||
..,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tags
|
tags
|
||||||
|
@ -144,6 +144,11 @@ impl SourceFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a source file without a real id and path, usually for testing.
|
||||||
|
pub fn detached(src: impl Into<String>) -> Self {
|
||||||
|
Self::new(SourceId(0), Path::new(""), src.into())
|
||||||
|
}
|
||||||
|
|
||||||
/// The file's abstract syntax tree.
|
/// The file's abstract syntax tree.
|
||||||
pub fn ast(&self) -> TypResult<Markup> {
|
pub fn ast(&self) -> TypResult<Markup> {
|
||||||
let red = RedNode::from_root(self.root.clone(), self.id);
|
let red = RedNode::from_root(self.root.clone(), self.id);
|
||||||
@ -155,11 +160,6 @@ impl SourceFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a source file without a real id and path, usually for testing.
|
|
||||||
pub fn detached(src: impl Into<String>) -> Self {
|
|
||||||
Self::new(SourceId(0), Path::new(""), src.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The id of the source file.
|
/// The id of the source file.
|
||||||
pub fn id(&self) -> SourceId {
|
pub fn id(&self) -> SourceId {
|
||||||
self.id
|
self.id
|
||||||
|
@ -6,9 +6,9 @@ pub use paper::*;
|
|||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::font::{
|
use ttf_parser::Tag;
|
||||||
FontFamily, FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric,
|
|
||||||
};
|
use crate::font::*;
|
||||||
use crate::geom::*;
|
use crate::geom::*;
|
||||||
|
|
||||||
/// Defines a set of properties a template can be instantiated with.
|
/// Defines a set of properties a template can be instantiated with.
|
||||||
@ -275,7 +275,7 @@ pub struct FontFeatures {
|
|||||||
/// Configuration of numbers features.
|
/// Configuration of numbers features.
|
||||||
pub numbers: NumberFeatures,
|
pub numbers: NumberFeatures,
|
||||||
/// Raw OpenType features to apply.
|
/// Raw OpenType features to apply.
|
||||||
pub raw: Vec<(String, u32)>,
|
pub raw: Vec<(Tag, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FontFeatures {
|
impl Default for FontFeatures {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user