diff --git a/.wt-consolidate b/.wt-consolidate new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-consolidate @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-delim b/.wt-delim new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-delim @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-display b/.wt-display new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-display @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-engine b/.wt-engine new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-engine @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-fill b/.wt-fill new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-fill @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-fonts b/.wt-fonts new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-fonts @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-hf b/.wt-hf new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-hf @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-keytips b/.wt-keytips new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-keytips @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-numval b/.wt-numval new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-numval @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-passthrough b/.wt-passthrough new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-passthrough @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-pivotfilter b/.wt-pivotfilter new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-pivotfilter @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/.wt-textfn b/.wt-textfn new file mode 160000 index 000000000..e1604d179 --- /dev/null +++ b/.wt-textfn @@ -0,0 +1 @@ +Subproject commit e1604d17915fe5a1f8d75fe9a5eef449226ec867 diff --git a/crates/xlsx/src/styles.rs b/crates/xlsx/src/styles.rs index c1f93aca9..d962881d3 100644 --- a/crates/xlsx/src/styles.rs +++ b/crates/xlsx/src/styles.rs @@ -59,11 +59,14 @@ fn bool_prop(e: &El, name: &str) -> bool { const DEFAULT_FONT_FAMILY: u8 = 2; const MAX_FONT_FAMILY: u8 = 14; +/// Longest font name kept, in characters (Excel's own limit). Every cell format copies its +/// font, so a long name repeated by many formats would otherwise multiply in memory. +const MAX_FONT_NAME: usize = 31; pub fn read_font(e: &El, palette: &[u32]) -> Font { let mut f = Font::default(); if let Some(n) = e.child("name").or_else(|| e.child("rFont")).and_then(|n| n.attr("val")) { - f.name = n.to_string(); + f.name = n.chars().take(MAX_FONT_NAME).collect(); } if let Some(sz) = e.child("sz").and_then(|s| s.attr_f64("val")) { f.size = sz.clamp(1.0, 409.0) as f32; @@ -277,14 +280,14 @@ fn read_protection(p: &El) -> Protection { Protection { locked: p.flag("locked", true), hidden: p.flag("hidden", false) } } -fn num_fmt_code(id: u32, custom: &HashMap) -> NumFmt { +fn num_fmt_code(id: u32, custom: &HashMap) -> NumFmt { if let Some(c) = custom.get(&id) { - return NumFmt::new(c); + return c.clone(); } NumFmt::new(builtin_format(id).unwrap_or("General")) } -fn read_xf(xf: &El, fonts: &[Font], fills: &[Fill], borders: &[Borders], fmts: &HashMap, checkboxes: &[bool]) -> Style { +fn read_xf(xf: &El, fonts: &[Font], fills: &[Fill], borders: &[Borders], fmts: &HashMap, checkboxes: &[bool]) -> Style { let mut s = Style::default(); if let Some(f) = xf.attr_u32("fontId").and_then(|i| fonts.get(i as usize)) { s.font = f.clone(); @@ -336,6 +339,8 @@ pub fn read_styles(root: &El, checkboxes: &[bool], minor_font: &str) -> StylesIn } } } + // One shared copy of each custom code, which every format using it points to. + let shared_fmts: HashMap = fmts.iter().map(|(id, code)| (*id, NumFmt::new(code))).collect(); // The scheme link only means something on a font in the body face; elsewhere it stays as a new font has it. let body_font = |e: &El| { let mut f = read_font(e, &palette); @@ -345,10 +350,14 @@ pub fn read_styles(root: &El, checkboxes: &[bool], minor_font: &str) -> StylesIn let fonts: Vec = root.child("fonts").map(|f| f.kids("font").map(body_font).collect()).unwrap_or_default(); let fills: Vec = root.child("fills").map(|f| f.kids("fill").map(|e| read_fill(e, &palette, false)).collect()).unwrap_or_default(); let borders: Vec = root.child("borders").map(|f| f.kids("border").map(|e| read_border(e, &palette)).collect()).unwrap_or_default(); - let xfs = - root.child("cellXfs").map(|x| x.kids("xf").map(|xf| read_xf(xf, &fonts, &fills, &borders, &fmts, checkboxes)).collect()).unwrap_or_default(); - let style_xfs: Vec