mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-24 10:16:59 -06:00
chore: resolve SonarCloud maintainability issues
- Replace lambda closures with method references (S1612) - Replace wildcard imports with explicit imports (S2208) - Refactor complex functions with extracted helpers (S3776) - Replace OR pattern with range pattern in math parser (S9047)
This commit is contained in:
@@ -124,7 +124,7 @@ fn main() -> ExitCode {
|
||||
Some("bench") => report(perf::bench(&args[1..])),
|
||||
Some("validate-pdf") => report(validate_pdf(args.get(1).map(String::as_str))),
|
||||
Some("links") => {
|
||||
use designcraft_engine::links::*;
|
||||
use designcraft_engine::links::{APP_PAGE, DISCORD, GITHUB, ISSUES, WEBSITE};
|
||||
outln!("Discord {DISCORD}\nWebsite {WEBSITE}\nApp page {APP_PAGE}\nGitHub {GITHUB}\nIssues {ISSUES}");
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
@@ -345,33 +345,7 @@ fn run(args: &[String]) -> Result<(), String> {
|
||||
}
|
||||
"--export" => {
|
||||
let out = val()?;
|
||||
match Export::of(&out)? {
|
||||
Export::Image => export(&mut s, &out, page, scale)?,
|
||||
Export::Pdf => {
|
||||
let mut p = pdf_opts.clone();
|
||||
p["path"] = json!(out);
|
||||
let r = s.execute("file.exportPdf", &p).map_err(|e| e.to_string())?;
|
||||
eprintln!("wrote {out} ({} pages, {} bytes)", r["pages"], r["bytes"]);
|
||||
for w in r["warnings"].as_array().into_iter().flatten() {
|
||||
eprintln!("warning: {}", w.as_str().unwrap_or_default());
|
||||
}
|
||||
}
|
||||
Export::Document => {
|
||||
s.execute("file.saveAs", &json!({"path": out})).map_err(|e| e.to_string())?;
|
||||
eprintln!("saved {out}");
|
||||
}
|
||||
Export::Pptx => {
|
||||
let r = s.execute("file.exportPptx", &json!({"path": out})).map_err(|e| e.to_string())?;
|
||||
eprintln!("wrote {out} ({} slides, {} bytes)", r["slides"], r["bytes"]);
|
||||
for w in r["warnings"].as_array().into_iter().flatten() {
|
||||
eprintln!("warning: {}", w.as_str().unwrap_or_default());
|
||||
}
|
||||
}
|
||||
Export::Command(cmd) => {
|
||||
let r = s.execute(cmd, &json!({"path": out})).map_err(|e| e.to_string())?;
|
||||
eprintln!("wrote {out} ({} bytes)", r["bytes"]);
|
||||
}
|
||||
}
|
||||
handle_export(&mut s, &out, page, scale, &pdf_opts)?;
|
||||
}
|
||||
"--all-pages" => {
|
||||
let dir = val()?;
|
||||
@@ -387,6 +361,37 @@ fn run(args: &[String]) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_export(s: &mut Session, out: &str, page: usize, scale: f64, pdf_opts: &Value) -> Result<(), String> {
|
||||
match Export::of(out)? {
|
||||
Export::Image => export(s, out, page, scale)?,
|
||||
Export::Pdf => {
|
||||
let mut p = pdf_opts.clone();
|
||||
p["path"] = json!(out);
|
||||
let r = s.execute("file.exportPdf", &p).map_err(|e| e.to_string())?;
|
||||
eprintln!("wrote {out} ({} pages, {} bytes)", r["pages"], r["bytes"]);
|
||||
for w in r["warnings"].as_array().into_iter().flatten() {
|
||||
eprintln!("warning: {}", w.as_str().unwrap_or_default());
|
||||
}
|
||||
}
|
||||
Export::Document => {
|
||||
s.execute("file.saveAs", &json!({"path": out})).map_err(|e| e.to_string())?;
|
||||
eprintln!("saved {out}");
|
||||
}
|
||||
Export::Pptx => {
|
||||
let r = s.execute("file.exportPptx", &json!({"path": out})).map_err(|e| e.to_string())?;
|
||||
eprintln!("wrote {out} ({} slides, {} bytes)", r["slides"], r["bytes"]);
|
||||
for w in r["warnings"].as_array().into_iter().flatten() {
|
||||
eprintln!("warning: {}", w.as_str().unwrap_or_default());
|
||||
}
|
||||
}
|
||||
Export::Command(cmd) => {
|
||||
let r = s.execute(cmd, &json!({"path": out})).map_err(|e| e.to_string())?;
|
||||
eprintln!("wrote {out} ({} bytes)", r["bytes"]);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A page as PNG, or as JPEG for `.jpg` and `.jpeg`.
|
||||
fn export(s: &mut Session, out: &str, page: usize, scale: f64) -> Result<(), String> {
|
||||
let st = s.doc().map_err(|e| e.to_string())?;
|
||||
|
||||
+10
-10
@@ -17,7 +17,7 @@ pub mod lab;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Mutex, OnceLock, RwLock};
|
||||
use std::sync::{Arc, Mutex, OnceLock, PoisonError, RwLock};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -201,7 +201,7 @@ static USER: RwLock<Vec<Arc<IccProfile>>> = RwLock::new(Vec::new());
|
||||
|
||||
fn builtin_rgb_cache(name: &str) -> Option<Arc<IccProfile>> {
|
||||
static CACHE: Mutex<Vec<Arc<IccProfile>>> = Mutex::new(Vec::new());
|
||||
let mut c = CACHE.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut c = CACHE.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
if let Some(p) = c.iter().find(|p| p.name == name) {
|
||||
return Some(p.clone());
|
||||
}
|
||||
@@ -211,7 +211,7 @@ fn builtin_rgb_cache(name: &str) -> Option<Arc<IccProfile>> {
|
||||
}
|
||||
|
||||
fn user_profile(name: &str) -> Option<Arc<IccProfile>> {
|
||||
USER.read().unwrap_or_else(|e| e.into_inner()).iter().find(|p| p.name == name).cloned()
|
||||
USER.read().unwrap_or_else(PoisonError::into_inner).iter().find(|p| p.name == name).cloned()
|
||||
}
|
||||
|
||||
/// The default CMYK space: Coated FOGRA39, or Generic CMYK should that profile be unusable.
|
||||
@@ -255,7 +255,7 @@ pub fn profiles() -> Vec<ProfileInfo> {
|
||||
.map(|n| ProfileInfo { name: (*n).into(), kind: ProfileKind::Rgb, builtin: true })
|
||||
.chain([COATED_FOGRA39, GENERIC_CMYK, DEVICE_CMYK].iter().map(|n| ProfileInfo { name: (*n).into(), kind: ProfileKind::Cmyk, builtin: true }))
|
||||
.collect();
|
||||
for p in USER.read().unwrap_or_else(|e| e.into_inner()).iter() {
|
||||
for p in USER.read().unwrap_or_else(PoisonError::into_inner).iter() {
|
||||
v.push(ProfileInfo { name: p.name.clone(), kind: p.kind, builtin: false });
|
||||
}
|
||||
v
|
||||
@@ -275,7 +275,7 @@ pub fn register_icc(bytes: &[u8], name: Option<String>) -> Result<ProfileInfo, C
|
||||
return Err(CmsError::Unsupported(format!("{}: no usable transform to/from sRGB", p.name)));
|
||||
}
|
||||
let info = ProfileInfo { name: p.name.clone(), kind: p.kind, builtin: false };
|
||||
let mut u = USER.write().unwrap_or_else(|e| e.into_inner());
|
||||
let mut u = USER.write().unwrap_or_else(PoisonError::into_inner);
|
||||
u.retain(|x| x.name != info.name);
|
||||
u.push(Arc::new(p));
|
||||
drop(u);
|
||||
@@ -522,7 +522,7 @@ impl Cms {
|
||||
/// A cached 3-D lookup table implementing [`Cms::proof_srgb`] for 8-bit pixels.
|
||||
pub fn proof_lut(&self, proof: &ProofSetup) -> Arc<ProofLut> {
|
||||
let key = format!("{:?}|{:?}|{:?}|{}", self.settings, proof.target, proof.intent, proof.simulate_paper);
|
||||
let mut cache = PROOF_CACHE.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut cache = PROOF_CACHE.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
if let Some((_, l)) = cache.iter().find(|(k, _)| *k == key) {
|
||||
return l.clone();
|
||||
}
|
||||
@@ -538,7 +538,7 @@ impl Cms {
|
||||
static PROOF_CACHE: Mutex<Vec<(String, Arc<ProofLut>)>> = Mutex::new(Vec::new());
|
||||
|
||||
fn clear_proof_cache() {
|
||||
PROOF_CACHE.lock().unwrap_or_else(|e| e.into_inner()).clear();
|
||||
PROOF_CACHE.lock().unwrap_or_else(PoisonError::into_inner).clear();
|
||||
}
|
||||
|
||||
fn cmyk4(v: Option<Vec<f32>>) -> Option<[f32; 4]> {
|
||||
@@ -704,10 +704,10 @@ pub fn generation() -> u64 {
|
||||
|
||||
/// The active colour-management context (Edit → Color Settings).
|
||||
pub fn active() -> Arc<Cms> {
|
||||
if let Some(c) = ACTIVE.read().unwrap_or_else(|e| e.into_inner()).as_ref() {
|
||||
if let Some(c) = ACTIVE.read().unwrap_or_else(PoisonError::into_inner).as_ref() {
|
||||
return c.clone();
|
||||
}
|
||||
let mut w = ACTIVE.write().unwrap_or_else(|e| e.into_inner());
|
||||
let mut w = ACTIVE.write().unwrap_or_else(PoisonError::into_inner);
|
||||
w.get_or_insert_with(|| Arc::new(Cms::default())).clone()
|
||||
}
|
||||
|
||||
@@ -721,7 +721,7 @@ pub fn set_active(settings: &ColorSettings) -> Result<(), CmsError> {
|
||||
let changed = active().settings != *settings;
|
||||
RGB_IS_SRGB.store(cms.rgb_is_srgb(), Ordering::Relaxed);
|
||||
CMYK_IS_DEVICE.store(matches!(cms.cmyk, CmykSpace::Device), Ordering::Relaxed);
|
||||
*ACTIVE.write().unwrap_or_else(|e| e.into_inner()) = Some(Arc::new(cms));
|
||||
*ACTIVE.write().unwrap_or_else(PoisonError::into_inner) = Some(Arc::new(cms));
|
||||
if changed {
|
||||
GENERATION.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ fn cjk_break(a: &Glyph, b: &Glyph, sp: &Spacing) -> bool {
|
||||
}
|
||||
|
||||
pub fn is_forced(c: char) -> bool {
|
||||
use designcraft_doc::story::*;
|
||||
use designcraft_doc::story::{FORCED_LINE_BREAK, is_break_char};
|
||||
c == FORCED_LINE_BREAK || is_break_char(c)
|
||||
}
|
||||
|
||||
|
||||
+13
-13
@@ -7,7 +7,7 @@
|
||||
//! can't be reused by other allocations while the entry lives.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, PoisonError};
|
||||
|
||||
use designcraft_doc::{Document, Item, Story, StoryId, Styles};
|
||||
|
||||
@@ -196,7 +196,7 @@ impl Cache {
|
||||
sig.push(std::hash::Hasher::finish(&h) as usize);
|
||||
}
|
||||
{
|
||||
let mut g = self.map.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut g = self.map.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
g.1 += 1;
|
||||
let stamp = g.1;
|
||||
if let Some(e) = g.0.get_mut(&key)
|
||||
@@ -216,7 +216,7 @@ impl Cache {
|
||||
&ComposeOptions { page_name, section_marker, page, running, label: None, xrefs: with_xrefs.then(|| self.xref_index(doc)) },
|
||||
&others.iter().map(|o| &**o).collect::<Vec<_>>(),
|
||||
));
|
||||
let mut g = self.map.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut g = self.map.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
let stamp = g.1;
|
||||
if g.0.len() > 4096 {
|
||||
g.0.retain(|_, e| stamp - e.stamp < 64);
|
||||
@@ -228,7 +228,7 @@ impl Cache {
|
||||
&& cross
|
||||
&& let Some(old) = replaced
|
||||
{
|
||||
self.previous.lock().unwrap_or_else(|e| e.into_inner()).insert(sid, (old.sig, old.out));
|
||||
self.previous.lock().unwrap_or_else(PoisonError::into_inner).insert(sid, (old.sig, old.out));
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -241,7 +241,7 @@ impl Cache {
|
||||
// Only the geometry/story part of the signature (variables etc. add to it).
|
||||
let matches = |s: &[usize]| s.len() >= sig.len() && s[..sig.len()] == sig[..];
|
||||
{
|
||||
let g = self.map.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let g = self.map.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
for cross in [true, false] {
|
||||
if let Some(e) = g.0.get(&(sid, ShownOn::Own, cross))
|
||||
&& matches(&e.sig)
|
||||
@@ -250,7 +250,7 @@ impl Cache {
|
||||
}
|
||||
}
|
||||
}
|
||||
let g = self.previous.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let g = self.previous.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
g.get(&sid).filter(|(s, _)| matches(s)).map(|(_, c)| c.clone())
|
||||
}
|
||||
|
||||
@@ -306,34 +306,34 @@ impl Cache {
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.map.lock().unwrap_or_else(|e| e.into_inner()).0.clear();
|
||||
*self.running.lock().unwrap_or_else(|e| e.into_inner()) = None;
|
||||
*self.xrefs.lock().unwrap_or_else(|e| e.into_inner()) = None;
|
||||
self.map.lock().unwrap_or_else(PoisonError::into_inner).0.clear();
|
||||
*self.running.lock().unwrap_or_else(PoisonError::into_inner) = None;
|
||||
*self.xrefs.lock().unwrap_or_else(PoisonError::into_inner) = None;
|
||||
}
|
||||
|
||||
/// Anchor pages for cross-references (rebuilt when the document changes).
|
||||
pub fn xref_index(&self, doc: &Document) -> Arc<crate::xref::XrefIndex> {
|
||||
let sig = doc_signature(doc);
|
||||
if let Some((s, r)) = &*self.xrefs.lock().unwrap_or_else(|e| e.into_inner())
|
||||
if let Some((s, r)) = &*self.xrefs.lock().unwrap_or_else(PoisonError::into_inner)
|
||||
&& *s == sig
|
||||
{
|
||||
return r.clone();
|
||||
}
|
||||
let r = Arc::new(crate::xref::XrefIndex::build(doc, &|sid| self.get(doc, sid, None)));
|
||||
*self.xrefs.lock().unwrap_or_else(|e| e.into_inner()) = Some((sig, r.clone()));
|
||||
*self.xrefs.lock().unwrap_or_else(PoisonError::into_inner) = Some((sig, r.clone()));
|
||||
r
|
||||
}
|
||||
|
||||
/// The running-header index for `doc` (rebuilt when the document changes).
|
||||
pub fn running_index(&self, doc: &Document) -> Arc<RunningIndex> {
|
||||
let sig = doc_signature(doc);
|
||||
if let Some((s, r)) = &*self.running.lock().unwrap_or_else(|e| e.into_inner())
|
||||
if let Some((s, r)) = &*self.running.lock().unwrap_or_else(PoisonError::into_inner)
|
||||
&& *s == sig
|
||||
{
|
||||
return r.clone();
|
||||
}
|
||||
let r = Arc::new(RunningIndex::build(doc, &|sid| self.get(doc, sid, None)));
|
||||
*self.running.lock().unwrap_or_else(|e| e.into_inner()) = Some((sig, r.clone()));
|
||||
*self.running.lock().unwrap_or_else(PoisonError::into_inner) = Some((sig, r.clone()));
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2892,7 +2892,7 @@ fn test_font(family: &str, os2_fields: Option<&[(usize, i16)]>) -> Vec<u8> {
|
||||
|
||||
/// [`test_font`] with OS/2 `sTypoAscender` set to `typo_ascender`, or without OS/2 for `None`.
|
||||
fn typo_test_font(family: &str, typo_ascender: Option<i16>) -> Vec<u8> {
|
||||
test_font(family, typo_ascender.map(|v| [(TYPO_ASCENDER, v)]).as_ref().map(|f| f.as_slice()))
|
||||
test_font(family, typo_ascender.map(|v| [(TYPO_ASCENDER, v)]).as_ref().map(<[_]>::as_slice))
|
||||
}
|
||||
|
||||
/// First baseline (frame space) of a 20 pt line in `family` in a frame at y = 36 with a 4 pt top
|
||||
|
||||
@@ -224,6 +224,23 @@ fn layout(styles: &[RunStyle], line: &mut [PlacedGlyph], members: &[usize]) -> f
|
||||
// Bounded, so a hostile value can't move a row to an infinite or huge coordinate.
|
||||
let spacing = if st.warichu_line_spacing.is_finite() { st.warichu_line_spacing.clamp(-16.0 * st.size, 16.0 * st.size) } else { 0.0 };
|
||||
let gap = if spacing == 0.0 { small } else { (small + spacing).max(0.0) };
|
||||
position_warichu_rows(line, members, &counts, &widths, block, old_x0, gap, st);
|
||||
let delta = block - old_span;
|
||||
shift_non_member_glyphs(line, members, &old_xs, old_x0, old_right, delta, scale);
|
||||
delta
|
||||
}
|
||||
|
||||
fn position_warichu_rows(
|
||||
line: &mut [PlacedGlyph],
|
||||
members: &[usize],
|
||||
counts: &[usize],
|
||||
widths: &[f64],
|
||||
block: f64,
|
||||
old_x0: f64,
|
||||
gap: f64,
|
||||
st: &RunStyle,
|
||||
) {
|
||||
let rows = counts.len().max(1);
|
||||
let mut off = 0_usize;
|
||||
for (li, &c) in counts.iter().enumerate() {
|
||||
let w = widths[li];
|
||||
@@ -242,7 +259,17 @@ fn layout(styles: &[RunStyle], line: &mut [PlacedGlyph], members: &[usize]) -> f
|
||||
}
|
||||
off += c;
|
||||
}
|
||||
let delta = block - old_span;
|
||||
}
|
||||
|
||||
fn shift_non_member_glyphs(
|
||||
line: &mut [PlacedGlyph],
|
||||
members: &[usize],
|
||||
old_xs: &[f64],
|
||||
old_x0: f64,
|
||||
old_right: f64,
|
||||
delta: f64,
|
||||
scale: f64,
|
||||
) {
|
||||
let mut placed: Vec<(f64, f64)> = old_xs.iter().enumerate().map(|(i, ox)| (*ox, line[members[i]].x)).collect();
|
||||
placed.sort_by(|a, b| a.0.total_cmp(&b.0));
|
||||
let mut member_at = vec![false; line.len()];
|
||||
@@ -265,7 +292,6 @@ fn layout(styles: &[RunStyle], line: &mut [PlacedGlyph], members: &[usize]) -> f
|
||||
g.x = anchor.1 + (g.x - anchor.0) * scale;
|
||||
}
|
||||
}
|
||||
delta
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -82,44 +82,49 @@ pub(crate) fn sync(d: &mut Document) {
|
||||
}
|
||||
}
|
||||
|
||||
/// InDesign's detection when objects become a container: objects in a row (or column) keep it,
|
||||
/// with Auto size and Space Between at their own spacing; others wrap in a row of their width.
|
||||
fn detect(bounds: &[Rect]) -> FlexLayout {
|
||||
let tol = 0.5;
|
||||
let in_line = |row: bool| {
|
||||
let mut v: Vec<&Rect> = bounds.iter().collect();
|
||||
v.sort_by(|a, b| if row { a.x0.total_cmp(&b.x0) } else { a.y0.total_cmp(&b.y0) });
|
||||
let apart = v.windows(2).all(|w| if row { w[1].x0 >= w[0].x1 - tol } else { w[1].y0 >= w[0].y1 - tol });
|
||||
let gaps: Vec<f64> = v.windows(2).map(|w| if row { w[1].x0 - w[0].x1 } else { w[1].y0 - w[0].y1 }).collect();
|
||||
(apart && bounds.len() > 1).then(|| gaps.iter().sum::<f64>() / gaps.len().max(1) as f64)
|
||||
};
|
||||
fn in_line_gap(bounds: &[Rect], row: bool, tol: f64) -> Option<f64> {
|
||||
let mut v: Vec<&Rect> = bounds.iter().collect();
|
||||
v.sort_by(|a, b| if row { a.x0.total_cmp(&b.x0) } else { a.y0.total_cmp(&b.y0) });
|
||||
let apart = v.windows(2).all(|w| if row { w[1].x0 >= w[0].x1 - tol } else { w[1].y0 >= w[0].y1 - tol });
|
||||
let gaps: Vec<f64> = v.windows(2).map(|w| if row { w[1].x0 - w[0].x1 } else { w[1].y0 - w[0].y1 }).collect();
|
||||
(apart && bounds.len() > 1).then(|| gaps.iter().sum::<f64>() / gaps.len().max(1) as f64)
|
||||
}
|
||||
|
||||
fn detect_align(bounds: &[Rect], row: bool, tol: f64) -> FlexAlign {
|
||||
let same = |f: &dyn Fn(&Rect) -> f64| bounds.windows(2).all(|w| (f(&w[0]) - f(&w[1])).abs() <= tol);
|
||||
let align = |row: bool| {
|
||||
let (a, c, e): (&dyn Fn(&Rect) -> f64, &dyn Fn(&Rect) -> f64, &dyn Fn(&Rect) -> f64) =
|
||||
if row { (&|r| r.y0, &|r| r.center().y, &|r| r.y1) } else { (&|r| r.x0, &|r| r.center().x, &|r| r.x1) };
|
||||
if same(a) {
|
||||
FlexAlign::Start
|
||||
} else if same(c) {
|
||||
FlexAlign::Center
|
||||
} else if same(e) {
|
||||
FlexAlign::End
|
||||
} else {
|
||||
FlexAlign::Start
|
||||
}
|
||||
};
|
||||
let auto = |gap: f64, row: bool| FlexLayout {
|
||||
let (a, c, e): (&dyn Fn(&Rect) -> f64, &dyn Fn(&Rect) -> f64, &dyn Fn(&Rect) -> f64) =
|
||||
if row { (&|r| r.y0, &|r| r.center().y, &|r| r.y1) } else { (&|r| r.x0, &|r| r.center().x, &|r| r.x1) };
|
||||
if same(a) {
|
||||
FlexAlign::Start
|
||||
} else if same(c) {
|
||||
FlexAlign::Center
|
||||
} else if same(e) {
|
||||
FlexAlign::End
|
||||
} else {
|
||||
FlexAlign::Start
|
||||
}
|
||||
}
|
||||
|
||||
fn auto_flex(gap: f64, row: bool, align: FlexAlign) -> FlexLayout {
|
||||
FlexLayout {
|
||||
direction: if row { FlexDirection::Row } else { FlexDirection::Column },
|
||||
justify: FlexJustify::SpaceBetween,
|
||||
align: align(row),
|
||||
align,
|
||||
width: FlexSize::Auto,
|
||||
height: FlexSize::Auto,
|
||||
gap_h: if row { gap.max(0.0) } else { 0.0 },
|
||||
gap_v: if row { 0.0 } else { gap.max(0.0) },
|
||||
..Default::default()
|
||||
};
|
||||
match (in_line(true), in_line(false)) {
|
||||
(Some(gap), _) => auto(gap, true),
|
||||
(None, Some(gap)) => auto(gap, false),
|
||||
}
|
||||
}
|
||||
|
||||
/// InDesign's detection when objects become a container: objects in a row (or column) keep it,
|
||||
/// with Auto size and Space Between at their own spacing; others wrap in a row of their width.
|
||||
fn detect(bounds: &[Rect]) -> FlexLayout {
|
||||
let tol = 0.5;
|
||||
match (in_line_gap(bounds, true, tol), in_line_gap(bounds, false, tol)) {
|
||||
(Some(gap), _) => auto_flex(gap, true, detect_align(bounds, true, tol)),
|
||||
(None, Some(gap)) => auto_flex(gap, false, detect_align(bounds, false, tol)),
|
||||
_ => FlexLayout { wrap: true, height: FlexSize::Auto, ..Default::default() },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2105,7 +2105,7 @@ fn open_type_features(s: &mut Session, _p: &Value) -> Result<Value> {
|
||||
continue;
|
||||
}
|
||||
let names: std::collections::BTreeSet<&String> = fonts.values().filter_map(|f| f.stylistic_sets.get(&set)).collect();
|
||||
let name = if names.len() == 1 { names.first().map(|n| n.to_string()) } else { None };
|
||||
let name = if names.len() == 1 { names.first().map(ToString::to_string) } else { None };
|
||||
let (applied, available) = measure(&tag);
|
||||
sets.push(json!({"set": set, "tag": tag, "name": name, "applied": applied, "available": available}));
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ impl Parser<'_> {
|
||||
'+' => Node::Sym("+".into(), Class::Bin),
|
||||
'-' => Node::Sym("−".into(), Class::Bin),
|
||||
'*' => Node::Sym("∗".into(), Class::Bin),
|
||||
'=' | '<' | '>' => Node::Sym(c.to_string(), Class::Rel),
|
||||
'<'..='>' => Node::Sym(c.to_string(), Class::Rel),
|
||||
',' | ';' => Node::Sym(c.to_string(), Class::Punct),
|
||||
'\'' => Node::Sym("′".into(), Class::Plain),
|
||||
c => Node::Sym(c.to_string(), Class::Plain),
|
||||
@@ -390,7 +390,7 @@ impl Parser<'_> {
|
||||
if self.peek().is_none() {
|
||||
break;
|
||||
}
|
||||
if self.s[self.i..].starts_with(&['\\', 'r', 'i', 'g', 'h', 't']) && !self.s.get(self.i + 6).is_some_and(|c| c.is_ascii_alphabetic()) {
|
||||
if self.s[self.i..].starts_with(&['\\', 'r', 'i', 'g', 'h', 't']) && !self.s.get(self.i + 6).is_some_and(char::is_ascii_alphabetic) {
|
||||
self.i += 6;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ fn remove_emptied(dir: &Path) {
|
||||
let path = e.path();
|
||||
let name = e.file_name();
|
||||
let name = name.to_string_lossy();
|
||||
let numbered = path.file_stem().and_then(|s| s.to_str()).is_some_and(|s| s.parse::<u64>().is_ok());
|
||||
let numbered = path.file_stem().and_then(std::ffi::OsStr::to_str).is_some_and(|s| s.parse::<u64>().is_ok());
|
||||
// Metadata whose document has gone, and a file a crash left half written.
|
||||
if (numbered && name.ends_with(".json")) || (name.starts_with(".designcraft-recovery-") && name.ends_with(".tmp")) {
|
||||
left.push(path);
|
||||
@@ -726,8 +726,8 @@ fn occupied_uids(dir: &Path) -> Result<std::collections::HashSet<u64>> {
|
||||
for entry in entries {
|
||||
let entry = entry.map_err(|e| EngineError::Other(format!("{}: {e}", dir.display())))?;
|
||||
let path = entry.path();
|
||||
if matches!(path.extension().and_then(|s| s.to_str()), Some("json" | "designcraft"))
|
||||
&& let Some(uid) = path.file_stem().and_then(|s| s.to_str()).and_then(|s| s.parse().ok())
|
||||
if matches!(path.extension().and_then(std::ffi::OsStr::to_str), Some("json" | "designcraft"))
|
||||
&& let Some(uid) = path.file_stem().and_then(std::ffi::OsStr::to_str).and_then(|s| s.parse().ok())
|
||||
{
|
||||
ids.insert(uid);
|
||||
}
|
||||
@@ -756,10 +756,10 @@ pub fn list(dir: &Path) -> Vec<(u64, Value)> {
|
||||
let Ok(rd) = std::fs::read_dir(dir) else { return out };
|
||||
for e in rd.flatten() {
|
||||
let p = e.path();
|
||||
if p.extension().and_then(|x| x.to_str()) != Some("designcraft") {
|
||||
if p.extension().and_then(std::ffi::OsStr::to_str) != Some("designcraft") {
|
||||
continue;
|
||||
}
|
||||
let Some(uid) = p.file_stem().and_then(|s| s.to_str()).and_then(|s| s.parse::<u64>().ok()) else { continue };
|
||||
let Some(uid) = p.file_stem().and_then(std::ffi::OsStr::to_str).and_then(|s| s.parse::<u64>().ok()) else { continue };
|
||||
// Metadata is a file on disk: anything but an object (corrupt, hand-edited) counts as none.
|
||||
let meta = std::fs::read_to_string(p.with_extension("json"))
|
||||
.ok()
|
||||
|
||||
+30
-30
@@ -3,7 +3,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::{Arc, Mutex, PoisonError, RwLock};
|
||||
|
||||
use kurbo::BezPath;
|
||||
use skrifa::instance::{Location, LocationRef, Size};
|
||||
@@ -150,10 +150,10 @@ impl FaceRef {
|
||||
pub fn of(face: &Arc<FontFace>) -> FaceRef {
|
||||
static LEAKED: RwLock<Vec<Option<&'static FontFace>>> = RwLock::new(Vec::new());
|
||||
let id = face.id as usize;
|
||||
if let Some(Some(f)) = LEAKED.read().unwrap_or_else(|e| e.into_inner()).get(id) {
|
||||
if let Some(Some(f)) = LEAKED.read().unwrap_or_else(PoisonError::into_inner).get(id) {
|
||||
return FaceRef(f);
|
||||
}
|
||||
let mut w = LEAKED.write().unwrap_or_else(|e| e.into_inner());
|
||||
let mut w = LEAKED.write().unwrap_or_else(PoisonError::into_inner);
|
||||
if w.len() <= id {
|
||||
w.resize(id + 1, None);
|
||||
}
|
||||
@@ -1037,7 +1037,7 @@ pub fn same_style(a: &str, b: &str) -> bool {
|
||||
}
|
||||
|
||||
fn norm(s: &str) -> String {
|
||||
s.chars().filter(|c| c.is_alphanumeric()).flat_map(|c| c.to_lowercase()).collect()
|
||||
s.chars().filter(|c| c.is_alphanumeric()).flat_map(char::to_lowercase).collect()
|
||||
}
|
||||
|
||||
/// Weight implied by a style name.
|
||||
@@ -1107,7 +1107,7 @@ impl FontDb {
|
||||
pub fn set_system_fallback(&self, on: bool) {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
self.sys.lock().unwrap_or_else(|e| e.into_inner()).enabled = on;
|
||||
self.sys.lock().unwrap_or_else(PoisonError::into_inner).enabled = on;
|
||||
}
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let _ = on;
|
||||
@@ -1123,20 +1123,20 @@ impl FontDb {
|
||||
}
|
||||
|
||||
fn read_faces(&self) -> std::sync::RwLockReadGuard<'_, Vec<Arc<FontFace>>> {
|
||||
self.faces.read().unwrap_or_else(|e| e.into_inner())
|
||||
self.faces.read().unwrap_or_else(PoisonError::into_inner)
|
||||
}
|
||||
|
||||
/// The system font catalog, scanned first if it hasn't been yet.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn read_catalog(&self) -> std::sync::RwLockReadGuard<'_, Vec<CatalogEntry>> {
|
||||
self.ensure_catalog();
|
||||
self.catalog.read().unwrap_or_else(|e| e.into_inner())
|
||||
self.catalog.read().unwrap_or_else(PoisonError::into_inner)
|
||||
}
|
||||
|
||||
/// What the document with font scope `scope` sees: its own fonts ahead of the shared ones.
|
||||
/// Scope 0 (a document without fonts of its own) or a closed scope sees the shared fonts.
|
||||
pub fn scoped(&self, scope: u32) -> ScopedFonts<'_> {
|
||||
let own = if scope == 0 { None } else { self.scopes.read().unwrap_or_else(|e| e.into_inner()).get(&scope).cloned() };
|
||||
let own = if scope == 0 { None } else { self.scopes.read().unwrap_or_else(PoisonError::into_inner).get(&scope).cloned() };
|
||||
ScopedFonts { db: self, own }
|
||||
}
|
||||
|
||||
@@ -1187,7 +1187,7 @@ impl FontDb {
|
||||
/// family's bold without its regular), skipping a family and style another thread has added
|
||||
/// meanwhile. Returns the number added.
|
||||
fn insert_faces(&self, new: Vec<FontFace>) -> usize {
|
||||
let mut faces = self.faces.write().unwrap_or_else(|e| e.into_inner());
|
||||
let mut faces = self.faces.write().unwrap_or_else(PoisonError::into_inner);
|
||||
let mut added = 0;
|
||||
for f in new {
|
||||
if !has_face(&faces, &f.family, &f.style) {
|
||||
@@ -1238,7 +1238,7 @@ impl FontDb {
|
||||
let count = first.unwrap_or_else(|| self.scan_font_dirs());
|
||||
// Retry characters and CJK chain families that newly installed fonts can now cover.
|
||||
// Reset outside scan_font_dirs: a chain lookup can hold sys during the initial scan.
|
||||
let mut sys = self.sys.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut sys = self.sys.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
sys.generation = sys.generation.wrapping_add(1);
|
||||
sys.misses.clear();
|
||||
sys.chain_tried.clear();
|
||||
@@ -1257,7 +1257,7 @@ impl FontDb {
|
||||
// Rescan first: a lookup after the faces are dropped finds the new files.
|
||||
let cataloged = self.load_system_fonts();
|
||||
let changed: Vec<std::path::PathBuf> = {
|
||||
let mut files = self.installed_files.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut files = self.installed_files.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
let mut changed: Vec<_> = files.iter().filter(|(p, stamp)| file_stamp(p).as_ref() != Some(*stamp)).map(|(p, _)| p.clone()).collect();
|
||||
changed.sort();
|
||||
for p in &changed {
|
||||
@@ -1268,15 +1268,15 @@ impl FontDb {
|
||||
if !changed.is_empty() {
|
||||
let stale = |f: &FontFace| matches!(&f.source, FontSource::Installed(p) if changed.contains(p));
|
||||
let mut dropped = std::collections::HashSet::new();
|
||||
self.faces.write().unwrap_or_else(|e| e.into_inner()).retain(|f| {
|
||||
self.faces.write().unwrap_or_else(PoisonError::into_inner).retain(|f| {
|
||||
let keep = !stale(f);
|
||||
if !keep {
|
||||
dropped.insert(f.id);
|
||||
}
|
||||
keep
|
||||
});
|
||||
self.instances.write().unwrap_or_else(|e| e.into_inner()).retain(|(base, _), f| !dropped.contains(base) && !stale(f));
|
||||
self.outlines.lock().unwrap_or_else(|e| e.into_inner()).retain(|(face, _), _| !dropped.contains(face));
|
||||
self.instances.write().unwrap_or_else(PoisonError::into_inner).retain(|(base, _), f| !dropped.contains(base) && !stale(f));
|
||||
self.outlines.lock().unwrap_or_else(PoisonError::into_inner).retain(|(face, _), _| !dropped.contains(face));
|
||||
log::debug!("reloading {} changed font files ({} faces)", changed.len(), dropped.len());
|
||||
}
|
||||
ReloadedFonts { cataloged, changed }
|
||||
@@ -1291,7 +1291,7 @@ impl FontDb {
|
||||
fn read_installed(&self, path: &std::path::Path) -> Option<Vec<u8>> {
|
||||
let stamp = file_stamp(path)?;
|
||||
let data = std::fs::read(path).ok()?;
|
||||
self.installed_files.lock().unwrap_or_else(|e| e.into_inner()).insert(path.to_path_buf(), stamp);
|
||||
self.installed_files.lock().unwrap_or_else(PoisonError::into_inner).insert(path.to_path_buf(), stamp);
|
||||
Some(data)
|
||||
}
|
||||
|
||||
@@ -1351,7 +1351,7 @@ impl FontDb {
|
||||
}
|
||||
let n = found.len();
|
||||
log::debug!("cataloged {n} system font faces");
|
||||
*self.catalog.write().unwrap_or_else(|e| e.into_inner()) = found;
|
||||
*self.catalog.write().unwrap_or_else(PoisonError::into_inner) = found;
|
||||
n
|
||||
}
|
||||
|
||||
@@ -1421,7 +1421,7 @@ impl FontDb {
|
||||
let name = path.file_name().map_or_else(|| path.display().to_string(), |n| n.to_string_lossy().into_owned());
|
||||
// The listed length skips oversized files unread.
|
||||
let meta = std::fs::metadata(path).ok();
|
||||
let listed = meta.as_ref().map_or(0, |m| m.len());
|
||||
let listed = meta.as_ref().map_or(0, std::fs::Metadata::len);
|
||||
let faces = if listed > MAX_DOCUMENT_FONT_BYTES {
|
||||
Err(too_large())
|
||||
} else if total.saturating_add(listed) > MAX_DOCUMENT_FONTS_TOTAL {
|
||||
@@ -1449,7 +1449,7 @@ impl FontDb {
|
||||
if !own.is_empty() {
|
||||
out.scope = NEXT_SCOPE.fetch_add(1, Ordering::Relaxed);
|
||||
out.faces = own.len();
|
||||
self.scopes.write().unwrap_or_else(|e| e.into_inner()).insert(out.scope, own.into());
|
||||
self.scopes.write().unwrap_or_else(PoisonError::into_inner).insert(out.scope, own.into());
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -1466,7 +1466,7 @@ impl FontDb {
|
||||
room: u64,
|
||||
) -> Result<(Vec<Arc<FontFace>>, u64), String> {
|
||||
use std::io::Read;
|
||||
if let Some((len, m, faces)) = self.document_files.lock().unwrap_or_else(|e| e.into_inner()).get(path)
|
||||
if let Some((len, m, faces)) = self.document_files.lock().unwrap_or_else(PoisonError::into_inner).get(path)
|
||||
&& (*len, *m) == (listed, modified)
|
||||
{
|
||||
return Ok((faces.clone(), listed));
|
||||
@@ -1494,14 +1494,14 @@ impl FontDb {
|
||||
if faces.is_empty() {
|
||||
return Err("not a font DesignCraft can read".into());
|
||||
}
|
||||
self.document_files.lock().unwrap_or_else(|e| e.into_inner()).insert(path.to_path_buf(), (listed, modified, faces.clone()));
|
||||
self.document_files.lock().unwrap_or_else(PoisonError::into_inner).insert(path.to_path_buf(), (listed, modified, faces.clone()));
|
||||
Ok((faces, len))
|
||||
}
|
||||
|
||||
/// Close a document's font scope: its fonts are no longer found (in it or anywhere). Their
|
||||
/// files stay read, for the document opening again.
|
||||
pub fn close_scope(&self, scope: u32) {
|
||||
self.scopes.write().unwrap_or_else(|e| e.into_inner()).remove(&scope);
|
||||
self.scopes.write().unwrap_or_else(PoisonError::into_inner).remove(&scope);
|
||||
}
|
||||
|
||||
/// The shared fonts' face for `family` + `style` (see [`ScopedFonts::face`]).
|
||||
@@ -1542,7 +1542,7 @@ impl FontDb {
|
||||
return false;
|
||||
}
|
||||
let generation = {
|
||||
let sys = self.sys.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let sys = self.sys.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
if !sys.enabled || sys.misses.contains(&c) {
|
||||
return false;
|
||||
}
|
||||
@@ -1558,12 +1558,12 @@ impl FontDb {
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut paths: Vec<std::path::PathBuf> = self.catalog.read().unwrap_or_else(|e| e.into_inner()).iter().map(|e| e.path.clone()).collect();
|
||||
let mut paths: Vec<std::path::PathBuf> = self.catalog.read().unwrap_or_else(PoisonError::into_inner).iter().map(|e| e.path.clone()).collect();
|
||||
paths.sort();
|
||||
paths.dedup();
|
||||
#[cfg(all(test, target_os = "linux"))]
|
||||
{
|
||||
let hook = self.fallback_snapshot_hook.lock().unwrap_or_else(|e| e.into_inner()).take();
|
||||
let hook = self.fallback_snapshot_hook.lock().unwrap_or_else(PoisonError::into_inner).take();
|
||||
if let Some(hook) = hook {
|
||||
let _ = hook.reached.send(());
|
||||
hook.resume.wait();
|
||||
@@ -1580,7 +1580,7 @@ impl FontDb {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
let mut sys = self.sys.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut sys = self.sys.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
if sys.generation == generation {
|
||||
sys.misses.insert(c);
|
||||
}
|
||||
@@ -1619,12 +1619,12 @@ impl FontDb {
|
||||
/// disappears.
|
||||
pub fn outline(&self, face: &FontFace, gid: u32) -> Arc<BezPath> {
|
||||
let key = (face.id, gid);
|
||||
if let Some(p) = self.outlines.lock().unwrap_or_else(|e| e.into_inner()).get(&key) {
|
||||
if let Some(p) = self.outlines.lock().unwrap_or_else(PoisonError::into_inner).get(&key) {
|
||||
return p.clone();
|
||||
}
|
||||
let drawn = font_outline(face, gid);
|
||||
let p = Arc::new(if gid == 0 && drawn.elements().is_empty() { self.missing_box(face).unwrap_or(drawn) } else { drawn });
|
||||
let mut cache = self.outlines.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut cache = self.outlines.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
if cache.len() >= OUTLINE_CACHE_MAX {
|
||||
cache.clear();
|
||||
}
|
||||
@@ -1986,7 +1986,7 @@ impl ScopedFonts<'_> {
|
||||
return Some(base);
|
||||
}
|
||||
let key = (base.id, style.to_string());
|
||||
if let Some(f) = self.db.instances.read().unwrap_or_else(|e| e.into_inner()).get(&key) {
|
||||
if let Some(f) = self.db.instances.read().unwrap_or_else(PoisonError::into_inner).get(&key) {
|
||||
return Some(f.clone());
|
||||
}
|
||||
let mut coords = base.coords.clone();
|
||||
@@ -2004,7 +2004,7 @@ impl ScopedFonts<'_> {
|
||||
}
|
||||
}
|
||||
let f = make_face(base.bytes.clone(), base.source.clone(), base.index, base.family.clone(), style.to_string(), coords)?;
|
||||
Some(self.db.instances.write().unwrap_or_else(|e| e.into_inner()).entry(key).or_insert_with(|| Arc::new(f)).clone())
|
||||
Some(self.db.instances.write().unwrap_or_else(PoisonError::into_inner).entry(key).or_insert_with(|| Arc::new(f)).clone())
|
||||
}
|
||||
|
||||
fn find(&self, family: &str, style: &str) -> Option<Arc<FontFace>> {
|
||||
@@ -2077,7 +2077,7 @@ impl ScopedFonts<'_> {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if !self.db.is_loaded(family) {
|
||||
// Held while loading, so a parallel lookup waits for the font instead of passing it by.
|
||||
let mut sys = self.db.sys.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut sys = self.db.sys.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
if sys.enabled && sys.chain_tried.insert(family) {
|
||||
self.db.load_cataloged(family);
|
||||
}
|
||||
|
||||
@@ -882,7 +882,7 @@ impl Renderer {
|
||||
let page = Rect::new(-l * page_w, -t * page_h, (1.0 - l) * page_w, (1.0 - t) * page_h);
|
||||
let Some(pm) = images::mip(&data, asset.page, page_w, on_screen) else { return };
|
||||
// A coloured image is already in the plate's inks (its colours come from `color_of`).
|
||||
let pm = match (colorize::colorized(f.doc, &g.fill, &asset.data, &pm), PLATE.with(|p| p.get())) {
|
||||
let pm = match (colorize::colorized(f.doc, &g.fill, &asset.data, &pm), PLATE.with(std::cell::Cell::get)) {
|
||||
(Some(coloured), _) => coloured,
|
||||
(None, Some(plate)) => plate_pixmap(&pm, plate),
|
||||
(None, None) => pm,
|
||||
@@ -913,7 +913,7 @@ pub(crate) fn cmyk_table() -> std::sync::Arc<Vec<[f32; 4]>> {
|
||||
type Lut = (designcraft_color::cms::ColorSettings, std::sync::Arc<Vec<[f32; 4]>>);
|
||||
static LUT: std::sync::Mutex<Option<Lut>> = std::sync::Mutex::new(None);
|
||||
let settings = designcraft_color::cms::active_settings();
|
||||
let mut g = LUT.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut g = LUT.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
match g.as_ref() {
|
||||
Some((s, t)) if *s == settings => t.clone(),
|
||||
_ => {
|
||||
@@ -961,7 +961,7 @@ fn plate_pixmap(pm: &std::sync::Arc<vello_cpu::Pixmap>, plate: u8) -> std::sync:
|
||||
let key = (std::sync::Arc::as_ptr(pm) as usize, plate);
|
||||
let settings = designcraft_color::cms::active_settings();
|
||||
{
|
||||
let mut guard = CACHE.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut guard = CACHE.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
if let Some((previous, map, _)) = guard.as_ref() {
|
||||
if *previous == settings {
|
||||
if let Some((_, derived)) = map.get(&key) {
|
||||
@@ -994,7 +994,7 @@ fn plate_pixmap(pm: &std::sync::Arc<vello_cpu::Pixmap>, plate: u8) -> std::sync:
|
||||
let out = std::sync::Arc::new(vello_cpu::Pixmap::from_parts(data, pm.width(), pm.height()));
|
||||
let bytes = (pm.width() as usize).saturating_mul(pm.height() as usize).saturating_mul(8);
|
||||
if bytes <= BUDGET {
|
||||
let mut guard = CACHE.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let mut guard = CACHE.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
let (previous, map, used) = guard.get_or_insert_with(|| (settings.clone(), Default::default(), 0));
|
||||
if *previous != settings || used.saturating_add(bytes) > BUDGET {
|
||||
map.clear();
|
||||
@@ -1024,7 +1024,7 @@ thread_local! {
|
||||
/// Screen indicators and placeholders are display sRGB, independent of the document's RGB
|
||||
/// working profile. Encode their inks only while drawing a process plate or CMYK blend pass.
|
||||
pub(crate) fn screen_color(rgb: [u8; 3], alpha: u8) -> peniko::Color {
|
||||
if PLATE.with(|plate| plate.get()).is_none() {
|
||||
if PLATE.with(std::cell::Cell::get).is_none() {
|
||||
return peniko::Color::from_rgba8(rgb[0], rgb[1], rgb[2], alpha);
|
||||
}
|
||||
let [c, m, y, k] = cmyk_in(&cmyk_table(), rgb.map(|v| v as f32 / 255.0));
|
||||
@@ -1032,7 +1032,7 @@ pub(crate) fn screen_color(rgb: [u8; 3], alpha: u8) -> peniko::Color {
|
||||
}
|
||||
|
||||
pub fn color_of(c: &designcraft_color::Color, alpha: f32) -> peniko::Color {
|
||||
if let Some(p) = PLATE.with(|p| p.get()) {
|
||||
if let Some(p) = PLATE.with(std::cell::Cell::get) {
|
||||
let cmyk = match *c {
|
||||
designcraft_color::Color::Cmyk { c, m, y, k } => [c, m, y, k],
|
||||
_ => c.to_cmyk_managed(designcraft_color::cms::Intent::RelativeColorimetric),
|
||||
@@ -1045,7 +1045,7 @@ pub fn color_of(c: &designcraft_color::Color, alpha: f32) -> peniko::Color {
|
||||
let v = ink(p.min(3) as usize);
|
||||
return peniko::Color::from_rgba8(v, v, v, a);
|
||||
}
|
||||
if RICH_BLACK.with(|r| r.get())
|
||||
if RICH_BLACK.with(std::cell::Cell::get)
|
||||
&& let designcraft_color::Color::Cmyk { c: cc, m, y, k } = *c
|
||||
&& cc <= 1e-3
|
||||
&& m <= 1e-3
|
||||
|
||||
Reference in New Issue
Block a user