mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Kerned PDF output
This commit is contained in:
parent
c0377de653
commit
0806af4aec
@ -24,7 +24,7 @@ fxhash = "0.2.1"
|
|||||||
image = { version = "0.23", default-features = false, features = ["png", "jpeg"] }
|
image = { version = "0.23", default-features = false, features = ["png", "jpeg"] }
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
miniz_oxide = "0.4"
|
miniz_oxide = "0.4"
|
||||||
pdf-writer = "0.3"
|
pdf-writer = { git = "https://github.com/typst/pdf-writer", rev = "818659b" }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
rustybuzz = "0.4"
|
rustybuzz = "0.4"
|
||||||
serde = { version = "1", features = ["derive", "rc"] }
|
serde = { version = "1", features = ["derive", "rc"] }
|
||||||
|
@ -14,8 +14,8 @@ use pdf_writer::{
|
|||||||
use ttf_parser::{name_id, GlyphId};
|
use ttf_parser::{name_id, GlyphId};
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::font::{Em, FaceId, FontStore};
|
use crate::font::{FaceId, FontStore};
|
||||||
use crate::geom::{self, Length, Size};
|
use crate::geom::{self, Em, Length, Size};
|
||||||
use crate::image::{Image, ImageId, ImageStore};
|
use crate::image::{Image, ImageId, ImageStore};
|
||||||
use crate::layout::{Element, Frame, Geometry, Paint};
|
use crate::layout::{Element, Frame, Geometry, Paint};
|
||||||
use crate::Context;
|
use crate::Context;
|
||||||
@ -140,7 +140,7 @@ impl<'a> PdfExporter<'a> {
|
|||||||
|
|
||||||
// We only write font switching actions when the used face changes. To
|
// We only write font switching actions when the used face changes. To
|
||||||
// do that, we need to remember the active face.
|
// do that, we need to remember the active face.
|
||||||
let mut face = None;
|
let mut face_id = None;
|
||||||
let mut size = Length::zero();
|
let mut size = Length::zero();
|
||||||
let mut fill: Option<Paint> = None;
|
let mut fill: Option<Paint> = None;
|
||||||
|
|
||||||
@ -159,17 +159,50 @@ impl<'a> PdfExporter<'a> {
|
|||||||
|
|
||||||
// Then, also check if we need to issue a font switching
|
// Then, also check if we need to issue a font switching
|
||||||
// action.
|
// action.
|
||||||
if face != Some(shaped.face_id) || shaped.size != size {
|
if face_id != Some(shaped.face_id) || shaped.size != size {
|
||||||
face = Some(shaped.face_id);
|
face_id = Some(shaped.face_id);
|
||||||
size = shaped.size;
|
size = shaped.size;
|
||||||
|
|
||||||
let name = format!("F{}", self.font_map.map(shaped.face_id));
|
let name = format!("F{}", self.font_map.map(shaped.face_id));
|
||||||
text.font(Name(name.as_bytes()), size.to_pt() as f32);
|
text.font(Name(name.as_bytes()), size.to_pt() as f32);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Respect individual glyph offsets.
|
let face = self.fonts.get(shaped.face_id);
|
||||||
|
|
||||||
|
// Position the text.
|
||||||
text.matrix(1.0, 0.0, 0.0, 1.0, x, y);
|
text.matrix(1.0, 0.0, 0.0, 1.0, x, y);
|
||||||
text.show(Str(&shaped.encode_glyphs_be()));
|
|
||||||
|
let mut positioned = text.show_positioned();
|
||||||
|
let mut adjustment = Em::zero();
|
||||||
|
let mut encoded = vec![];
|
||||||
|
|
||||||
|
// Write the glyphs with kerning adjustments.
|
||||||
|
for glyph in &shaped.glyphs {
|
||||||
|
adjustment += glyph.x_offset;
|
||||||
|
|
||||||
|
if !adjustment.is_zero() {
|
||||||
|
if !encoded.is_empty() {
|
||||||
|
positioned.show(Str(&encoded));
|
||||||
|
encoded.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
positioned.adjust(-adjustment.to_pdf());
|
||||||
|
adjustment = Em::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded.push((glyph.id >> 8) as u8);
|
||||||
|
encoded.push((glyph.id & 0xff) as u8);
|
||||||
|
|
||||||
|
if let Some(advance) = face.advance(glyph.id) {
|
||||||
|
adjustment += glyph.x_advance - advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustment -= glyph.x_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !encoded.is_empty() {
|
||||||
|
positioned.show(Str(&encoded));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Element::Geometry(ref geometry, paint) => {
|
Element::Geometry(ref geometry, paint) => {
|
||||||
|
54
src/font.rs
54
src/font.rs
@ -2,15 +2,13 @@
|
|||||||
|
|
||||||
use std::collections::{hash_map::Entry, HashMap};
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::ops::Add;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use decorum::N64;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ttf_parser::name_id;
|
use ttf_parser::{name_id, GlyphId};
|
||||||
|
|
||||||
use crate::geom::Length;
|
use crate::geom::Em;
|
||||||
use crate::loading::{FileHash, Loader};
|
use crate::loading::{FileHash, Loader};
|
||||||
|
|
||||||
/// A unique identifier for a loaded font face.
|
/// A unique identifier for a loaded font face.
|
||||||
@ -255,6 +253,13 @@ impl Face {
|
|||||||
Em::from_units(units, self.units_per_em)
|
Em::from_units(units, self.units_per_em)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Look up the horizontal advance width of a glyph.
|
||||||
|
pub fn advance(&self, glyph: u16) -> Option<Em> {
|
||||||
|
self.ttf
|
||||||
|
.glyph_hor_advance(GlyphId(glyph))
|
||||||
|
.map(|units| self.to_em(units))
|
||||||
|
}
|
||||||
|
|
||||||
/// Look up a vertical metric.
|
/// Look up a vertical metric.
|
||||||
pub fn vertical_metric(&self, metric: VerticalFontMetric) -> Em {
|
pub fn vertical_metric(&self, metric: VerticalFontMetric) -> Em {
|
||||||
match metric {
|
match metric {
|
||||||
@ -267,47 +272,6 @@ impl Face {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A length in em units.
|
|
||||||
///
|
|
||||||
/// `1em` is the same as the font size.
|
|
||||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
|
||||||
pub struct Em(N64);
|
|
||||||
|
|
||||||
impl Em {
|
|
||||||
/// The zero length.
|
|
||||||
pub fn zero() -> Self {
|
|
||||||
Self(N64::from(0.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an em length.
|
|
||||||
pub fn new(em: f64) -> Self {
|
|
||||||
Self(N64::from(em))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert units to an em length at the given units per em.
|
|
||||||
pub fn from_units(units: impl Into<f64>, units_per_em: f64) -> Self {
|
|
||||||
Self(N64::from(units.into() / units_per_em))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The number of em units.
|
|
||||||
pub fn get(self) -> f64 {
|
|
||||||
self.0.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert to a length at the given font size.
|
|
||||||
pub fn to_length(self, font_size: Length) -> Length {
|
|
||||||
self.get() * font_size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for Em {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, other: Self) -> Self {
|
|
||||||
Self(self.0 + other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identifies a vertical metric of a font.
|
/// Identifies a vertical metric of a font.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum VerticalFontMetric {
|
pub enum VerticalFontMetric {
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
use decorum::N64;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// An angle.
|
/// An angle.
|
||||||
|
112
src/geom/em.rs
Normal file
112
src/geom/em.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// A length that is relative to the font size.
|
||||||
|
///
|
||||||
|
/// `1em` is the same as the font size.
|
||||||
|
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Em(N64);
|
||||||
|
|
||||||
|
impl Em {
|
||||||
|
/// The zero length.
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Self(N64::from(0.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The font size.
|
||||||
|
pub fn one() -> Self {
|
||||||
|
Self(N64::from(1.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an font-relative length.
|
||||||
|
pub fn new(em: f64) -> Self {
|
||||||
|
Self(N64::from(em))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create font units at the given units per em.
|
||||||
|
pub fn from_units(units: impl Into<f64>, units_per_em: f64) -> Self {
|
||||||
|
Self(N64::from(units.into() / units_per_em))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert to a length at the given font size.
|
||||||
|
pub fn to_length(self, font_size: Length) -> Length {
|
||||||
|
self.get() * font_size
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of em units.
|
||||||
|
pub fn get(self) -> f64 {
|
||||||
|
self.0.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the length is zero.
|
||||||
|
pub fn is_zero(self) -> bool {
|
||||||
|
self.0 == 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Em {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Em {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}em", self.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Em {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self {
|
||||||
|
Self(-self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Em {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, other: Self) -> Self {
|
||||||
|
Self(self.0 + other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub_impl!(Em - Em -> Em);
|
||||||
|
|
||||||
|
impl Mul<f64> for Em {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, other: f64) -> Self {
|
||||||
|
Self(self.0 * other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Em> for f64 {
|
||||||
|
type Output = Em;
|
||||||
|
|
||||||
|
fn mul(self, other: Em) -> Em {
|
||||||
|
other * self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<f64> for Em {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, other: f64) -> Self {
|
||||||
|
Self(self.0 / other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for Em {
|
||||||
|
type Output = f64;
|
||||||
|
|
||||||
|
fn div(self, other: Self) -> f64 {
|
||||||
|
self.get() / other.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assign_impl!(Em += Em);
|
||||||
|
assign_impl!(Em -= Em);
|
||||||
|
assign_impl!(Em *= f64);
|
||||||
|
assign_impl!(Em /= f64);
|
@ -1,5 +1,3 @@
|
|||||||
use decorum::N64;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A fractional length.
|
/// A fractional length.
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
use decorum::N64;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// An absolute length.
|
/// An absolute length.
|
||||||
|
@ -5,6 +5,7 @@ mod macros;
|
|||||||
mod align;
|
mod align;
|
||||||
mod angle;
|
mod angle;
|
||||||
mod dir;
|
mod dir;
|
||||||
|
mod em;
|
||||||
mod fr;
|
mod fr;
|
||||||
mod gen;
|
mod gen;
|
||||||
mod length;
|
mod length;
|
||||||
@ -19,6 +20,7 @@ mod spec;
|
|||||||
pub use align::*;
|
pub use align::*;
|
||||||
pub use angle::*;
|
pub use angle::*;
|
||||||
pub use dir::*;
|
pub use dir::*;
|
||||||
|
pub use em::*;
|
||||||
pub use fr::*;
|
pub use fr::*;
|
||||||
pub use gen::*;
|
pub use gen::*;
|
||||||
pub use length::*;
|
pub use length::*;
|
||||||
@ -35,6 +37,9 @@ use std::fmt::{self, Debug, Display, Formatter};
|
|||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
|
||||||
|
use decorum::N64;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Generic access to a structure's components.
|
/// Generic access to a structure's components.
|
||||||
pub trait Get<Index> {
|
pub trait Get<Index> {
|
||||||
/// The structure's component type.
|
/// The structure's component type.
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// A bezier path.
|
/// A bezier path.
|
||||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// A point in 2D.
|
/// A point in 2D.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use decorum::N64;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A relative length.
|
/// A relative length.
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// A size in 2D.
|
/// A size in 2D.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub struct Size {
|
pub struct Size {
|
||||||
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use super::{Constrained, Constraints};
|
use super::{Constrained, Constraints};
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::font::FaceId;
|
use crate::font::FaceId;
|
||||||
use crate::geom::{Length, Path, Point, Size};
|
use crate::geom::{Em, Length, Path, Point, Size};
|
||||||
use crate::image::ImageId;
|
use crate::image::ImageId;
|
||||||
|
|
||||||
/// A finished layout with elements at fixed positions.
|
/// A finished layout with elements at fixed positions.
|
||||||
@ -130,27 +130,15 @@ pub struct Text {
|
|||||||
pub glyphs: Vec<Glyph>,
|
pub glyphs: Vec<Glyph>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Text {
|
|
||||||
/// Encode the glyph ids into a big-endian byte buffer.
|
|
||||||
pub fn encode_glyphs_be(&self) -> Vec<u8> {
|
|
||||||
let mut bytes = Vec::with_capacity(2 * self.glyphs.len());
|
|
||||||
for glyph in &self.glyphs {
|
|
||||||
bytes.push((glyph.id >> 8) as u8);
|
|
||||||
bytes.push((glyph.id & 0xff) as u8);
|
|
||||||
}
|
|
||||||
bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A glyph in a run of shaped text.
|
/// A glyph in a run of shaped text.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Glyph {
|
pub struct Glyph {
|
||||||
/// The glyph's index in the face.
|
/// The glyph's index in the face.
|
||||||
pub id: u16,
|
pub id: u16,
|
||||||
/// The advance width of the glyph.
|
/// The advance width of the glyph.
|
||||||
pub x_advance: Length,
|
pub x_advance: Em,
|
||||||
/// The horizontal offset of the glyph.
|
/// The horizontal offset of the glyph.
|
||||||
pub x_offset: Length,
|
pub x_offset: Em,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A geometric shape.
|
/// A geometric shape.
|
||||||
|
@ -6,7 +6,7 @@ use rustybuzz::UnicodeBuffer;
|
|||||||
use super::{Element, Frame, Glyph, LayoutContext, Text};
|
use super::{Element, Frame, Glyph, LayoutContext, Text};
|
||||||
use crate::eval::{FontState, LineState};
|
use crate::eval::{FontState, LineState};
|
||||||
use crate::font::{Face, FaceId, FontVariant, LineMetrics};
|
use crate::font::{Face, FaceId, FontVariant, LineMetrics};
|
||||||
use crate::geom::{Dir, Length, Point, Size};
|
use crate::geom::{Dir, Em, Length, Point, Size};
|
||||||
use crate::layout::Geometry;
|
use crate::layout::Geometry;
|
||||||
use crate::util::SliceExt;
|
use crate::util::SliceExt;
|
||||||
|
|
||||||
@ -72,9 +72,9 @@ pub struct ShapedGlyph {
|
|||||||
/// The glyph's index in the face.
|
/// The glyph's index in the face.
|
||||||
pub glyph_id: u16,
|
pub glyph_id: u16,
|
||||||
/// The advance width of the glyph.
|
/// The advance width of the glyph.
|
||||||
pub x_advance: Length,
|
pub x_advance: Em,
|
||||||
/// The horizontal offset of the glyph.
|
/// The horizontal offset of the glyph.
|
||||||
pub x_offset: Length,
|
pub x_offset: Em,
|
||||||
/// The start index of the glyph in the source text.
|
/// The start index of the glyph in the source text.
|
||||||
pub text_index: usize,
|
pub text_index: usize,
|
||||||
/// Whether splitting the shaping result before this glyph would yield the
|
/// Whether splitting the shaping result before this glyph would yield the
|
||||||
@ -106,7 +106,7 @@ impl<'a> ShapedText<'a> {
|
|||||||
x_advance: glyph.x_advance,
|
x_advance: glyph.x_advance,
|
||||||
x_offset: glyph.x_offset,
|
x_offset: glyph.x_offset,
|
||||||
});
|
});
|
||||||
width += glyph.x_advance;
|
width += glyph.x_advance.to_length(text.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.push(pos, Element::Text(text));
|
frame.push(pos, Element::Text(text));
|
||||||
@ -267,8 +267,8 @@ fn shape_segment<'a>(
|
|||||||
glyphs.push(ShapedGlyph {
|
glyphs.push(ShapedGlyph {
|
||||||
face_id,
|
face_id,
|
||||||
glyph_id: info.glyph_id as u16,
|
glyph_id: info.glyph_id as u16,
|
||||||
x_advance: face.to_em(pos[i].x_advance).to_length(size),
|
x_advance: face.to_em(pos[i].x_advance),
|
||||||
x_offset: face.to_em(pos[i].x_offset).to_length(size),
|
x_offset: face.to_em(pos[i].x_offset),
|
||||||
text_index: base + cluster,
|
text_index: base + cluster,
|
||||||
safe_to_break: !info.unsafe_to_break(),
|
safe_to_break: !info.unsafe_to_break(),
|
||||||
});
|
});
|
||||||
@ -342,7 +342,9 @@ fn measure(
|
|||||||
let mut width = Length::zero();
|
let mut width = Length::zero();
|
||||||
let mut top = Length::zero();
|
let mut top = Length::zero();
|
||||||
let mut bottom = Length::zero();
|
let mut bottom = Length::zero();
|
||||||
let mut expand_vertical = |face: &Face| {
|
|
||||||
|
// Expand top and bottom by reading the face's vertical metrics.
|
||||||
|
let mut expand = |face: &Face| {
|
||||||
top.set_max(face.vertical_metric(state.top_edge).to_length(state.size));
|
top.set_max(face.vertical_metric(state.top_edge).to_length(state.size));
|
||||||
bottom.set_max(-face.vertical_metric(state.bottom_edge).to_length(state.size));
|
bottom.set_max(-face.vertical_metric(state.bottom_edge).to_length(state.size));
|
||||||
};
|
};
|
||||||
@ -352,17 +354,17 @@ fn measure(
|
|||||||
// first available font.
|
// first available font.
|
||||||
for family in state.families() {
|
for family in state.families() {
|
||||||
if let Some(face_id) = ctx.fonts.select(family, state.variant) {
|
if let Some(face_id) = ctx.fonts.select(family, state.variant) {
|
||||||
expand_vertical(ctx.fonts.get(face_id));
|
expand(ctx.fonts.get(face_id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (face_id, group) in glyphs.group_by_key(|g| g.face_id) {
|
for (face_id, group) in glyphs.group_by_key(|g| g.face_id) {
|
||||||
let face = ctx.fonts.get(face_id);
|
let face = ctx.fonts.get(face_id);
|
||||||
expand_vertical(face);
|
expand(face);
|
||||||
|
|
||||||
for glyph in group {
|
for glyph in group {
|
||||||
width += glyph.x_advance;
|
width += glyph.x_advance.to_length(state.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,7 +444,7 @@ fn draw_text(canvas: &mut sk::Pixmap, ts: sk::Transform, ctx: &Context, text: &T
|
|||||||
for glyph in &text.glyphs {
|
for glyph in &text.glyphs {
|
||||||
let units_per_em = ttf.units_per_em();
|
let units_per_em = ttf.units_per_em();
|
||||||
let s = text.size.to_pt() as f32 / units_per_em as f32;
|
let s = text.size.to_pt() as f32 / units_per_em as f32;
|
||||||
let dx = glyph.x_offset.to_pt() as f32;
|
let dx = glyph.x_offset.to_length(text.size).to_pt() as f32;
|
||||||
let ts = ts.pre_translate(x + dx, 0.0);
|
let ts = ts.pre_translate(x + dx, 0.0);
|
||||||
|
|
||||||
// Try drawing SVG if present.
|
// Try drawing SVG if present.
|
||||||
@ -481,7 +481,7 @@ fn draw_text(canvas: &mut sk::Pixmap, ts: sk::Transform, ctx: &Context, text: &T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x += glyph.x_advance.to_pt() as f32;
|
x += glyph.x_advance.to_length(text.size).to_pt() as f32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user