Test [font] 🧣

This commit is contained in:
Laurenz 2020-12-17 15:43:30 +01:00
parent 7e91c8dc87
commit 6f111f9410
13 changed files with 66 additions and 28 deletions

BIN
fonts/PTSans-Bold.ttf Normal file

Binary file not shown.

BIN
fonts/PTSans-BoldItalic.ttf Normal file

Binary file not shown.

BIN
fonts/PTSans-Italic.ttf Normal file

Binary file not shown.

View File

@ -60,7 +60,7 @@ impl ResourceLoader {
} }
}; };
Some((id, self.get_loaded(id))) Some((id, self.loaded(id)))
} }
/// Retrieve a previously loaded resource by its id. /// Retrieve a previously loaded resource by its id.
@ -68,7 +68,7 @@ impl ResourceLoader {
/// # Panics /// # Panics
/// This panics if no resource with this id was loaded. /// This panics if no resource with this id was loaded.
#[track_caller] #[track_caller]
pub fn get_loaded<R: 'static>(&self, id: ResourceId) -> &R { pub fn loaded<R: 'static>(&self, id: ResourceId) -> &R {
self.entries[id.0].downcast_ref().expect("bad resource type") self.entries[id.0].downcast_ref().expect("bad resource type")
} }
} }

View File

@ -51,7 +51,7 @@ impl<'a> PdfExporter<'a> {
match element { match element {
LayoutElement::Text(shaped) => fonts.insert(shaped.face), LayoutElement::Text(shaped) => fonts.insert(shaped.face),
LayoutElement::Image(image) => { LayoutElement::Image(image) => {
let img = env.resources.get_loaded::<ImageResource>(image.res); let img = env.resources.loaded::<ImageResource>(image.res);
if img.buf.color().has_alpha() { if img.buf.color().has_alpha() {
alpha_masks += 1; alpha_masks += 1;
} }
@ -181,7 +181,7 @@ impl<'a> PdfExporter<'a> {
fn write_fonts(&mut self) { fn write_fonts(&mut self) {
for (refs, face_id) in self.refs.fonts().zip(self.fonts.layout_indices()) { for (refs, face_id) in self.refs.fonts().zip(self.fonts.layout_indices()) {
let owned_face = self.env.fonts.get_loaded(face_id); let owned_face = self.env.fonts.face(face_id);
let face = owned_face.get(); let face = owned_face.get();
let name = face let name = face
@ -292,7 +292,7 @@ impl<'a> PdfExporter<'a> {
let mut masks_seen = 0; let mut masks_seen = 0;
for (id, resource) in self.refs.images().zip(self.images.layout_indices()) { for (id, resource) in self.refs.images().zip(self.images.layout_indices()) {
let img = self.env.resources.get_loaded::<ImageResource>(resource); let img = self.env.resources.loaded::<ImageResource>(resource);
let (width, height) = img.buf.dimensions(); let (width, height) = img.buf.dimensions();
// Add the primary image. // Add the primary image.

View File

@ -21,10 +21,10 @@ use crate::prelude::*;
pub fn align(mut args: Args, ctx: &mut EvalContext) -> Value { pub fn align(mut args: Args, ctx: &mut EvalContext) -> Value {
let snapshot = ctx.state.clone(); let snapshot = ctx.state.clone();
let body = args.find::<SynTree>(); let body = args.find::<SynTree>();
let first = args.get::<_, Spanned<AlignArg>>(ctx, 0); let first = args.get::<_, Spanned<SpecAlign>>(ctx, 0);
let second = args.get::<_, Spanned<AlignArg>>(ctx, 1); let second = args.get::<_, Spanned<SpecAlign>>(ctx, 1);
let hor = args.get::<_, Spanned<AlignArg>>(ctx, "horizontal"); let hor = args.get::<_, Spanned<SpecAlign>>(ctx, "horizontal");
let ver = args.get::<_, Spanned<AlignArg>>(ctx, "vertical"); let ver = args.get::<_, Spanned<SpecAlign>>(ctx, "vertical");
args.done(ctx); args.done(ctx);
let prev_main = ctx.state.align.main; let prev_main = ctx.state.align.main;
@ -58,7 +58,7 @@ pub fn align(mut args: Args, ctx: &mut EvalContext) -> Value {
} else { } else {
// We don't know the axis: This has to be a `center` alignment for a // We don't know the axis: This has to be a `center` alignment for a
// positional argument. // positional argument.
debug_assert_eq!(arg, AlignArg::Center); debug_assert_eq!(arg, SpecAlign::Center);
if had.main && had.cross { if had.main && had.cross {
ctx.diag(error!(span, "duplicate alignment")); ctx.diag(error!(span, "duplicate alignment"));
@ -108,7 +108,7 @@ pub fn align(mut args: Args, ctx: &mut EvalContext) -> Value {
/// An argument to `[align]`. /// An argument to `[align]`.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
enum AlignArg { enum SpecAlign {
Left, Left,
Right, Right,
Top, Top,
@ -116,7 +116,7 @@ enum AlignArg {
Center, Center,
} }
convert_ident!(AlignArg, "alignment", |v| match v { convert_ident!(SpecAlign, "alignment", |v| match v {
"left" => Some(Self::Left), "left" => Some(Self::Left),
"right" => Some(Self::Right), "right" => Some(Self::Right),
"top" => Some(Self::Top), "top" => Some(Self::Top),
@ -125,7 +125,7 @@ convert_ident!(AlignArg, "alignment", |v| match v {
_ => None, _ => None,
}); });
impl AlignArg { impl SpecAlign {
/// The specific axis this alignment refers to. /// The specific axis this alignment refers to.
/// ///
/// Returns `None` if this is `Center` since the axis is unknown. /// Returns `None` if this is `Center` since the axis is unknown.
@ -140,7 +140,7 @@ impl AlignArg {
} }
} }
impl Switch for AlignArg { impl Switch for SpecAlign {
type Other = Align; type Other = Align;
fn switch(self, flow: Flow) -> Self::Other { fn switch(self, flow: Flow) -> Self::Other {
@ -163,7 +163,7 @@ impl Switch for AlignArg {
} }
} }
impl Display for AlignArg { impl Display for SpecAlign {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(match self { f.pad(match self {
Self::Left => "left", Self::Left => "left",

View File

@ -71,13 +71,6 @@ pub fn font(mut args: Args, ctx: &mut EvalContext) -> Value {
} }
} }
let mut needs_flattening = false;
let list: Vec<_> = args.find_all::<StringLike>().map(|s| s.to_lowercase()).collect();
if !list.is_empty() {
Rc::make_mut(&mut ctx.state.font.families).list = list;
needs_flattening = true;
}
if let Some(style) = args.get::<_, FontStyle>(ctx, "style") { if let Some(style) = args.get::<_, FontStyle>(ctx, "style") {
ctx.state.font.variant.style = style; ctx.state.font.variant.style = style;
} }
@ -90,6 +83,13 @@ pub fn font(mut args: Args, ctx: &mut EvalContext) -> Value {
ctx.state.font.variant.stretch = stretch; ctx.state.font.variant.stretch = stretch;
} }
let mut needs_flattening = false;
let list: Vec<_> = args.find_all::<StringLike>().map(|s| s.to_lowercase()).collect();
if !list.is_empty() {
Rc::make_mut(&mut ctx.state.font.families).list = list;
needs_flattening = true;
}
for (class, dict) in args.find_all_str::<Spanned<ValueDict>>() { for (class, dict) in args.find_all_str::<Spanned<ValueDict>>() {
let fallback = Args(dict) let fallback = Args(dict)
.find_all::<StringLike>() .find_all::<StringLike>()
@ -100,12 +100,12 @@ pub fn font(mut args: Args, ctx: &mut EvalContext) -> Value {
needs_flattening = true; needs_flattening = true;
} }
args.done(ctx);
if needs_flattening { if needs_flattening {
Rc::make_mut(&mut ctx.state.font.families).flatten(); Rc::make_mut(&mut ctx.state.font.families).flatten();
} }
args.done(ctx);
if let Some(body) = body { if let Some(body) = body {
body.eval(ctx); body.eval(ctx);
ctx.state = snapshot; ctx.state = snapshot;

View File

@ -82,8 +82,8 @@ pub fn shape(
for c in chars { for c in chars {
let query = FaceQuery { fallback: fallback.iter(), variant, c }; let query = FaceQuery { fallback: fallback.iter(), variant, c };
if let Some((id, owned_face)) = loader.query(query) { if let Some(id) = loader.query(query) {
let face = owned_face.get(); let face = loader.face(id).get();
let (glyph, width) = match lookup_glyph(face, c, font_size) { let (glyph, width) = match lookup_glyph(face, c, font_size) {
Some(v) => v, Some(v) => v,
None => continue, None => continue,

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,18 @@
// Test font fallback.
// Source Sans Pro + Segoe UI Emoji.
Emoji: 🏀
// CMU Serif + Noto Emoji.
[font: "CMU Serif", "Noto Emoji"][Emoji: 🏀]
// Class definitions.
[font: math=("CMU Serif", "Latin Modern Math", "Noto Emoji")]
[font: math][Math: α + β 3]
// Class redefinition.
[font: sans-serif=("Noto Emoji",)]
[font: sans-serif=("Archivo", sans-serif)]
New sans-serif. 🚀
// TODO: Add tests for other scripts.

View File

@ -0,0 +1,20 @@
// Test configuring font properties.
[font: "PT Sans", 10pt]
// Set same font size in three different ways.
[font: 20pt][A]
[font: 200%][A]
[font: 15pt + 50%][A]
// Do nothing.
[font][Normal]
// Set style (is available).
[font: style=italic][Italic]
// Set weight (is available).
[font: weight=bold][Bold]
// Set stretch (not available, matching closest).
[font: stretch=ultra-condensed][Condensed]

View File

@ -278,7 +278,7 @@ fn draw(layouts: &[BoxLayout], env: &Env, pixel_per_pt: f32) -> Canvas {
} }
fn draw_text(canvas: &mut Canvas, pos: Point, env: &Env, shaped: &Shaped) { fn draw_text(canvas: &mut Canvas, pos: Point, env: &Env, shaped: &Shaped) {
let face = env.fonts.get_loaded(shaped.face).get(); let face = env.fonts.face(shaped.face).get();
for (&glyph, &offset) in shaped.glyphs.iter().zip(&shaped.offsets) { for (&glyph, &offset) in shaped.glyphs.iter().zip(&shaped.offsets) {
let units_per_em = face.units_per_em().unwrap_or(1000); let units_per_em = face.units_per_em().unwrap_or(1000);
@ -304,7 +304,7 @@ fn draw_text(canvas: &mut Canvas, pos: Point, env: &Env, shaped: &Shaped) {
} }
fn draw_image(canvas: &mut Canvas, pos: Point, env: &Env, img: &ImageElement) { fn draw_image(canvas: &mut Canvas, pos: Point, env: &Env, img: &ImageElement) {
let buf = &env.resources.get_loaded::<ImageResource>(img.res).buf; let buf = &env.resources.loaded::<ImageResource>(img.res).buf;
let mut pixmap = Pixmap::new(buf.width(), buf.height()).unwrap(); let mut pixmap = Pixmap::new(buf.width(), buf.height()).unwrap();
for ((_, _, src), dest) in buf.pixels().zip(pixmap.pixels_mut()) { for ((_, _, src), dest) in buf.pixels().zip(pixmap.pixels_mut()) {