fix(block-cache): address PR211 review follow-ups

- expand_defn: dedup the <1px baseline LOD branch the same way the <5px
  greek branch does, so colour-split MTEXT no longer stacks N overlapping
  baselines (one per \C segment) over the same OBB.
- sysfont: memoise canonical_family_name process-wide. resolve_font calls
  it once per word on the MTEXT measure hot path and Face::resolve re-runs
  it right after; the fontdb query + linear family scans were uncached.
- dimension/multileader/table: reword the 6 fill_tris_low FIXMEs. They
  cited a stale line and the wrong consumer — these fills render on the
  top-level path (panic-safe .get().unwrap_or), not the block cache, so
  they cannot trip emit_wire's debug_assert. State the real status:
  latent f32-precision debt, not a crash. Also fix the mis-indented
  text-fill WireModel in dimension.rs.
- tests: add a host-independent colour-split test (two \C segments in a
  block keep ≥2 distinct wire colours — guards the per-wire colour fix)
  and a TTF-gated UTM fill test (paired, non-zero fill_tris_low). Note the
  arial-style test's LFF-fallback limitation.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-28 21:57:51 +03:00
1 parent a84da122f4
commit a93271c1bd
6 files changed
+174 -31

No files matched your search

+12 -8
View File
@@ -1261,9 +1261,11 @@ fn tessellate_dimension_inner(
plinegen: true,
vp_scissor: None,
fill_tris: geom.arrow_fill,
// FIXME: fill_tris_low left empty — needs double-single split to match
// fill_tris. Any geometry from this path inside a block definition will
// trip the debug_assert_eq! in emit_wire (block_cache.rs:1397).
// fill_tris_low intentionally empty: this fill renders on the top-level
// path, where consumers (face3d_gpu, xclip) treat a short low half as
// all-zero, so it draws at f32 precision (sub-metre error at UTM scale)
// — not a crash. Follow-up: double-single-split via points_to_ds to
// match emit_wire's paired fill path.
fill_tris_low: Vec::new(),
});
@@ -1296,11 +1298,13 @@ fn tessellate_dimension_inner(
aabb: WireModel::UNBOUNDED_AABB,
plinegen: true,
vp_scissor: None,
fill_tris: rect,
// FIXME: fill_tris_low left empty — needs double-single split to match
// fill_tris. Any geometry from this path inside a block definition will
// trip the debug_assert_eq! in emit_wire (block_cache.rs:1397).
fill_tris_low: Vec::new(),
fill_tris: rect,
// fill_tris_low intentionally empty: this fill renders on the
// top-level path, where consumers (face3d_gpu, xclip) treat a
// short low half as all-zero, so it draws at f32 precision
// (sub-metre error at UTM scale) — not a crash. Follow-up:
// double-single-split via points_to_ds to match emit_wire.
fill_tris_low: Vec::new(),
});
}
}
+15 -9
View File
@@ -1304,9 +1304,11 @@ impl MultiLeaderTess for MultiLeader {
plinegen: true,
vp_scissor: None,
fill_tris: arrow_fill,
// FIXME: fill_tris_low left empty — needs double-single split to match
// fill_tris. Any geometry from this path inside a block definition will
// trip the debug_assert_eq! in emit_wire (block_cache.rs:1397).
// fill_tris_low intentionally empty: this fill renders on the
// top-level path, where consumers (face3d_gpu, xclip) treat a short
// low half as all-zero, so it draws at f32 precision (sub-metre
// error at UTM scale) — not a crash. Follow-up: double-single-split
// via points_to_ds to match emit_wire's paired fill path.
fill_tris_low: Vec::new(),
});
@@ -1596,9 +1598,11 @@ impl MultiLeaderTess for MultiLeader {
plinegen: true,
vp_scissor: None,
fill_tris: greek_tris,
// FIXME: fill_tris_low left empty — needs double-single split to match
// fill_tris. Any geometry from this path inside a block definition will
// trip the debug_assert_eq! in emit_wire (block_cache.rs:1397).
// fill_tris_low intentionally empty: this fill renders on
// the top-level path, where consumers treat a short low
// half as all-zero, so it draws at f32 precision (sub-
// metre error at UTM scale) — not a crash. Follow-up:
// double-single-split via points_to_ds to match emit_wire.
fill_tris_low: Vec::new(),
});
}
@@ -1676,9 +1680,11 @@ impl MultiLeaderTess for MultiLeader {
plinegen: true,
vp_scissor: None,
fill_tris: text_fill_tris,
// FIXME: fill_tris_low left empty — needs double-single split to match
// fill_tris. Any geometry from this path inside a block definition will
// trip the debug_assert_eq! in emit_wire (block_cache.rs:1397).
// fill_tris_low intentionally empty: this fill renders on
// the top-level path, where consumers treat a short low
// half as all-zero, so it draws at f32 precision (sub-
// metre error at UTM scale) — not a crash. Follow-up:
// double-single-split via points_to_ds to match emit_wire.
fill_tris_low: Vec::new(),
});
}
+5 -3
View File
@@ -755,9 +755,11 @@ pub fn tessellate_table(
plinegen: true,
vp_scissor: None,
fill_tris,
// FIXME: fill_tris_low left empty — needs double-single split to match
// fill_tris. Any geometry from this path inside a block definition will
// trip the debug_assert_eq! in emit_wire (block_cache.rs:1397).
// fill_tris_low intentionally empty: this fill renders on the
// top-level path, where consumers (face3d_gpu, xclip) treat a
// short low half as all-zero, so it draws at f32 precision
// (sub-metre error at UTM scale) — not a crash. Follow-up:
// double-single-split via points_to_ds to match emit_wire.
fill_tris_low: Vec::new(),
}
};
+11 -1
View File
@@ -1138,6 +1138,17 @@ fn expand_defn(
}
} else {
if h_px < 1.0 {
// Colour-split MTEXT: only the first outline
// wire from a source entity emits the baseline
// substitute. Siblings share the same
// text_obb_local and would stack identical
// overlapping lines (last colour wins) — the
// same dedup the greek branch does, one tier
// down.
if lw.text_obb_local == last_lod_obb {
continue;
}
last_lod_obb = lw.text_obb_local;
emit_text_baseline(lw, accum_xform, ctx, out, wpp);
continue;
}
@@ -1431,7 +1442,6 @@ fn emit_wire(
entry.fill_tris.push([hx, hy, hz]);
entry.fill_tris_low.push([lx, ly, lz]);
}
}
fn transform_tangent(
+22 -1
View File
@@ -6,7 +6,8 @@
// TTF glyph engine). LFF stroke fonts stay separate — this is purely the
// TrueType side of the renderer.
use std::sync::OnceLock;
use std::collections::HashMap;
use std::sync::{Mutex, OnceLock};
struct SysFonts {
db: fontdb::Database,
@@ -38,7 +39,27 @@ pub fn families() -> &'static [String] {
}
/// Resolve a requested family name to the canonical installed system family name (with exact case).
///
/// Memoised process-wide: `resolve_font` calls this once per word on the MTEXT
/// measure hot path for inline-`\f` TTF runs, and `Face::resolve` re-runs it
/// immediately after — the underlying fontdb query plus linear family scans are
/// not free. The cache keys on the raw request string; results are stable for
/// the process lifetime (the font DB is loaded once via `OnceLock`).
pub fn canonical_family_name(family: &str) -> Option<String> {
static CACHE: OnceLock<Mutex<HashMap<String, Option<String>>>> = OnceLock::new();
let cache = CACHE.get_or_init(|| Mutex::new(HashMap::new()));
if let Some(hit) = cache.lock().unwrap().get(family) {
return hit.clone();
}
let resolved = canonical_family_name_uncached(family);
cache
.lock()
.unwrap()
.insert(family.to_string(), resolved.clone());
resolved
}
fn canonical_family_name_uncached(family: &str) -> Option<String> {
let db = &fonts().db;
// 1. Try exact match first