forked from 1b-agent/opencadstudio-upstream
feat(text): parse TEXT via acadrust + extend SDF text to MTEXT
Two related steps for the text pipeline: - TEXT parsing now goes through acadrust's parse_plain_text (like MTEXT uses parse_mtext). text::acad_text_encode parses the value's %% codes — including %%u/%%o underline/overline and %%nnn — and re-encodes to the stroke tessellator's \L/\O + resolved-Unicode grammar, so OCS no longer tokenizes TEXT %% codes itself. (ATTRIB/TOLERANCE/DIMENSION still use the local tokenizer for now.) Bumps the acadrust pin to the commit that completes the TEXT/MTEXT control-code set. - SDF text (OCS_TEXT_SDF) now covers MTEXT and every text-producing entity, not just top-level TEXT. TextStroke carries a GlyphRun (layout params); the collector walks convert()'s TruckObject::Text runs and applies annotation scale exactly as tessellate does for strokes. layout_glyph_quads shares lff::tokenize_run so %% specials resolve and \L/\O decorations are skipped (decoration LINES in SDF are still TODO). Verified: stroke rendering unchanged with the flag off; SDF glyphs render correctly for TEXT and MTEXT with OCS_TEXT_SDF=1. 154 lib tests green. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
b88e5e4ad5
commit
d528a3e2a5
9 files changed
+149
-28
No files matched your search
@@ -70,11 +70,22 @@ pub fn layout_glyph_quads(
|
||||
let mut cursor_x = 0.0f32;
|
||||
let mut quads = Vec::new();
|
||||
|
||||
for ch in text.chars() {
|
||||
if ch == ' ' {
|
||||
cursor_x += face.word_spacing();
|
||||
continue;
|
||||
}
|
||||
// Same token walk as `tessellate_text_run` (LFF branch): DXF `%%` specials
|
||||
// resolve to glyphs, spaces/missing advance the pen, decoration toggles emit
|
||||
// no glyph (they render as lines on the stroke path).
|
||||
for tok in crate::scene::text::lff::tokenize_run(text) {
|
||||
let ch = match tok {
|
||||
crate::scene::text::lff::Tok::Glyph(c) => c,
|
||||
crate::scene::text::lff::Tok::Space => {
|
||||
cursor_x += face.word_spacing();
|
||||
continue;
|
||||
}
|
||||
crate::scene::text::lff::Tok::Missing => {
|
||||
cursor_x += 6.0 + face.letter_spacing() * tracking;
|
||||
continue;
|
||||
}
|
||||
crate::scene::text::lff::Tok::Deco(..) => continue,
|
||||
};
|
||||
match atlas.get_or_insert(font_name, ch) {
|
||||
Some(e) => {
|
||||
let (lo, hi) = (e.plane_min, e.plane_max);
|
||||
@@ -91,8 +102,7 @@ pub fn layout_glyph_quads(
|
||||
cursor_x += e.advance + face.letter_spacing() * tracking;
|
||||
}
|
||||
None => {
|
||||
// No ink (whitespace glyph) or atlas full: advance only, using
|
||||
// the glyph's own advance when the font knows it.
|
||||
// No ink (whitespace glyph) or atlas full: advance only.
|
||||
let adv = face.glyph(ch).map(|g| g.advance).unwrap_or(6.0);
|
||||
cursor_x += adv + face.letter_spacing() * tracking;
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ pub fn get_font(name: &str) -> &'static Font {
|
||||
|
||||
/// Decoration line a token toggles.
|
||||
#[derive(Clone, Copy)]
|
||||
enum Deco {
|
||||
pub(crate) enum Deco {
|
||||
Under,
|
||||
Over,
|
||||
Strike,
|
||||
@@ -202,7 +202,7 @@ enum Deco {
|
||||
/// How a decoration token changes state. `\L`/`\O`/`\K` turn on (idempotent),
|
||||
/// `\l`/`\o`/`\k` turn off; `%%u`/`%%o` flip.
|
||||
#[derive(Clone, Copy)]
|
||||
enum Op {
|
||||
pub(crate) enum Op {
|
||||
On,
|
||||
Off,
|
||||
Toggle,
|
||||
@@ -211,7 +211,7 @@ enum Op {
|
||||
/// One unit of a text run after inline-code resolution. Shared by the stroke
|
||||
/// (LFF) and shaped (TTF) renderers so both interpret the DXF inline grammar
|
||||
/// — `\L…\l` decorations and `%%` specials — identically.
|
||||
enum Tok {
|
||||
pub(crate) enum Tok {
|
||||
/// A renderable character (DXF `%%d`/`%%p`/`%%c`/`%%nnn` already resolved).
|
||||
Glyph(char),
|
||||
/// A literal space.
|
||||
@@ -225,7 +225,7 @@ enum Tok {
|
||||
|
||||
/// Resolve a run's inline codes into a flat token stream. Mirrors the original
|
||||
/// inline parser in `tessellate_text_run` exactly (verified by the golden test).
|
||||
fn tokenize_run(text: &str) -> Vec<Tok> {
|
||||
pub(crate) fn tokenize_run(text: &str) -> Vec<Tok> {
|
||||
let mut toks = Vec::new();
|
||||
let mut chars = text.chars().peekable();
|
||||
while let Some(ch) = chars.next() {
|
||||
|
||||
Reference in new issue
Block a user