use std::collections::BTreeMap;
use zenith_core::{Diagnostic, PropertyValue, ResolvedToken, ResolvedValue, TableNode, dim_to_px};
use super::super::paint::resolve_property_color;
use super::place::CellRect;
const QUANTIZE: f64 = 100.0;
#[inline]
fn quantize(v: f64) -> i64 {
(v * QUANTIZE).round() as i64
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(super) struct EdgeKey {
ax: i64,
ay: i64,
bx: i64,
by: i64,
}
impl EdgeKey {
fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
let (qx1, qy1, qx2, qy2) = (quantize(x1), quantize(y1), quantize(x2), quantize(y2));
if (qx1, qy1) <= (qx2, qy2) {
EdgeKey {
ax: qx1,
ay: qy1,
bx: qx2,
by: qy2,
}
} else {
EdgeKey {
ax: qx2,
ay: qy2,
bx: qx1,
by: qy1,
}
}
}
}
pub(super) struct EdgeStyle {
pub(super) x1: f64,
pub(super) y1: f64,
pub(super) x2: f64,
pub(super) y2: f64,
pub(super) color: crate::ir::Color,
pub(super) stroke_width: f64,
is_explicit: bool,
}
fn try_insert_edge(acc: &mut BTreeMap<EdgeKey, EdgeStyle>, key: EdgeKey, candidate: EdgeStyle) {
let should_insert = match acc.get(&key) {
None => true,
Some(existing) => {
candidate.is_explicit || !existing.is_explicit
}
};
if should_insert {
acc.insert(key, candidate);
}
}
pub(super) fn resolve_border_width(
prop: Option<&PropertyValue>,
resolved: &BTreeMap<String, ResolvedToken>,
default: f64,
) -> f64 {
match prop {
Some(PropertyValue::TokenRef(token_id)) => match resolved.get(token_id.as_str()) {
Some(rt) => match &rt.value {
ResolvedValue::Dimension(dim) => dim_to_px(dim.value, &dim.unit).unwrap_or(default),
ResolvedValue::Color(_)
| ResolvedValue::CmykColor { .. }
| ResolvedValue::Number(_)
| ResolvedValue::FontFamily(_)
| ResolvedValue::FontWeight(_)
| ResolvedValue::Gradient(_)
| ResolvedValue::Shadow(_)
| ResolvedValue::Filter(_)
| ResolvedValue::Mask(_) => default,
},
None => default,
},
Some(PropertyValue::Dimension(dim)) => dim_to_px(dim.value, &dim.unit).unwrap_or(default),
Some(PropertyValue::Literal(_)) | Some(PropertyValue::DataRef(_)) | None => default,
}
}
pub(super) fn accumulate_cell_edges(
table: &TableNode,
cell: &zenith_core::TableCell,
rect: &CellRect,
opacity: f64,
resolved: &BTreeMap<String, ResolvedToken>,
diagnostics: &mut Vec<Diagnostic>,
acc: &mut BTreeMap<EdgeKey, EdgeStyle>,
) {
let border_prop: Option<&PropertyValue> = cell.border.as_ref().or(table.border.as_ref());
let Some(prop) = border_prop else { return };
let Some(mut color) = resolve_property_color(prop, resolved, diagnostics, &table.id) else {
return;
};
color.a = (color.a as f64 * opacity).round() as u8;
let bw = resolve_border_width(
cell.border_width.as_ref().or(table.border_width.as_ref()),
resolved,
1.0,
)
.max(0.0);
if bw <= 0.0 {
return;
}
let is_explicit = cell.border.is_some();
let x0 = rect.x;
let y0 = rect.y;
let x1 = rect.x + rect.w;
let y1 = rect.y + rect.h;
for (ex1, ey1, ex2, ey2) in [
(x0, y0, x1, y0), (x0, y1, x1, y1), (x0, y0, x0, y1), (x1, y0, x1, y1), ] {
let key = EdgeKey::new(ex1, ey1, ex2, ey2);
let candidate = EdgeStyle {
x1: ex1,
y1: ey1,
x2: ex2,
y2: ey2,
color,
stroke_width: bw,
is_explicit,
};
try_insert_edge(acc, key, candidate);
}
}