mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-29 04:36:47 -06:00
CJK: ICF top and bottom from the font's BASE table for grid and character alignment
This commit is contained in:
@@ -16,10 +16,6 @@ use crate::shape::Glyph;
|
||||
/// Most grid lines one line or paragraph takes (input-derived).
|
||||
pub(crate) const MAX_GYOUDORI: u32 = 100;
|
||||
|
||||
/// The ideographic character face's inset from the em box, top and bottom, as a share of the em.
|
||||
/// An approximation: fonts with a `BASE` table give `icft` / `icfb`, which aren't read yet.
|
||||
const ICF_INSET: f64 = 0.05;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum Anchor {
|
||||
First,
|
||||
@@ -36,21 +32,22 @@ fn anchor(r: Reference) -> Anchor {
|
||||
}
|
||||
|
||||
/// The line's grid reference point below its baseline (negative = above), from its largest
|
||||
/// character's em box ([`crate::cjk_em_box`], as the leading model measures it).
|
||||
/// character's em box ([`crate::cjk_em_box`], as the leading model measures it) or ICF box
|
||||
/// ([`crate::cjk_icf_box`]).
|
||||
pub(crate) fn reference_offset(line: &[Glyph], r: Reference) -> f64 {
|
||||
if r == Reference::Baseline {
|
||||
return 0.0;
|
||||
}
|
||||
let Some(g) = line.iter().filter(|g| g.adv > 0.0).max_by(|a, b| a.size.total_cmp(&b.size)) else { return 0.0 };
|
||||
let (top, bottom) = crate::cjk_em_box(g);
|
||||
let inset = (bottom - top) * ICF_INSET;
|
||||
let (icf_top, icf_bottom) = crate::cjk_icf_box(g);
|
||||
match r {
|
||||
Reference::Baseline => 0.0,
|
||||
Reference::EmTop => top,
|
||||
Reference::EmCenter => (top + bottom) / 2.0,
|
||||
Reference::EmBottom => bottom,
|
||||
Reference::IcfTop => top + inset,
|
||||
Reference::IcfBottom => bottom - inset,
|
||||
Reference::IcfTop => icf_top,
|
||||
Reference::IcfBottom => icf_bottom,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2087,6 +2087,17 @@ fn cjk_em_box(g: &Glyph) -> (f64, f64) {
|
||||
let top = -height * g.ascent / (g.ascent + g.descent).max(1e-9);
|
||||
(top, top + height)
|
||||
}
|
||||
/// The ideographic character face (ICF) box relative to the baseline: the em box of
|
||||
/// [`cjk_em_box`] inset by the font's own ICF insets (`BASE` `icft`/`icfb`, else 5% of the em).
|
||||
fn cjk_icf_box(g: &Glyph) -> (f64, f64) {
|
||||
let (top, bottom) = cjk_em_box(g);
|
||||
let (em_top, em_bottom) = g.face.em_box();
|
||||
let (icf_top, icf_bottom) = g.face.icf_box();
|
||||
let em = (em_top - em_bottom).max(1e-9);
|
||||
let height = bottom - top;
|
||||
let inset = |v: f64| if v.is_finite() { v.clamp(0.0, 0.5) } else { 0.05 };
|
||||
(top + inset((em_top - icf_top) / em) * height, bottom - inset((icf_bottom - em_bottom) / em) * height)
|
||||
}
|
||||
fn cjk_alignment_shift(g: &Glyph, reference: &Glyph) -> f64 {
|
||||
use designcraft_doc::cjk::CharacterAlignment as A;
|
||||
let (t, b) = cjk_em_box(g);
|
||||
@@ -2096,8 +2107,8 @@ fn cjk_alignment_shift(g: &Glyph, reference: &Glyph) -> f64 {
|
||||
A::EmTop => t - rt,
|
||||
A::EmCenter => (t + b - rt - rb) / 2.0,
|
||||
A::EmBottom => b - rb,
|
||||
A::IcfTop => reference.ascent - g.ascent,
|
||||
A::IcfBottom => g.descent - reference.descent,
|
||||
A::IcfTop => cjk_icf_box(g).0 - cjk_icf_box(reference).0,
|
||||
A::IcfBottom => cjk_icf_box(g).1 - cjk_icf_box(reference).1,
|
||||
}
|
||||
}
|
||||
fn cjk_line_reference(line: &[Glyph]) -> f64 {
|
||||
|
||||
Reference in New Issue
Block a user