mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-07 12:13:14 +00:00
fix(format): bound the characters Sketch text runs write in all
This commit is contained in:
@@ -14,6 +14,9 @@ use super::tree::{Cx, color};
|
||||
const MAX_CHARS: usize = 1 << 20;
|
||||
/// Most runs read from one text layer.
|
||||
const MAX_RUNS: usize = 10_000;
|
||||
/// Most characters that styled runs may write in all, overlaps counted again (a run's range is
|
||||
/// rewritten in full, even where later runs overwrite it).
|
||||
const MAX_RUN_WORK: usize = 16 * MAX_CHARS;
|
||||
|
||||
/// Fill `node` (a TEXT node) from text layer `l`.
|
||||
pub(crate) fn node(cx: &mut Cx, l: &Value, node: &mut JsonMap<String, Value>) {
|
||||
@@ -80,10 +83,16 @@ pub(crate) fn node(cx: &mut Cx, l: &Value, node: &mut JsonMap<String, Value>) {
|
||||
// Runs that differ from the first: a style id per UTF-16 unit.
|
||||
let mut ids = vec![0u64; units];
|
||||
let mut table = JsonMap::new();
|
||||
let mut work = 0usize;
|
||||
for (start, end, s) in &styles {
|
||||
if *s == base {
|
||||
continue;
|
||||
}
|
||||
work = work.saturating_add(end.saturating_sub(*start));
|
||||
if work > MAX_RUN_WORK {
|
||||
cx.warn("text whose styled runs overlap a great deal keeps the first runs' styles");
|
||||
break;
|
||||
}
|
||||
let id = table.len() as u64 + 1;
|
||||
table.insert(id.to_string(), s.clone());
|
||||
for slot in ids.get_mut(*start..*end).into_iter().flatten() {
|
||||
|
||||
@@ -271,3 +271,13 @@ fn later_runs_dont_inherit_the_first_runs_settings() {
|
||||
assert_eq!(second.line_height, figcraft_doc::LineHeight::Auto, "{second:?}");
|
||||
assert!(second.variations.is_empty(), "{second:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runs_that_overlap_a_great_deal_stop_being_applied() {
|
||||
// 17 runs over the whole of a text of 2^20 characters: 17 × 2^20 writes without the limit.
|
||||
let n = 1 << 20;
|
||||
let mut runs = vec![(0, 1, "Helvetica", 10.0, BLACK)];
|
||||
runs.extend((0..17).map(|i| (0, n, "Helvetica", 11.0 + f64::from(i), BLACK)));
|
||||
let (_, warnings) = open(vec![text("Long", 0.0, 0.0, 200.0, 20.0, &"a".repeat(n), &runs)]);
|
||||
assert!(warnings.iter().any(|w| w.contains("overlap a great deal")), "{warnings:?}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user