refactor(io): R13/R14 plot flags come from the codec now

opencadcodec a35f43e reads R13/R14 LAYER records as plottable, the root
cause #1507 worked around on load; drop the host-side correction. Its
tests stay and now cover the codec fix end to end. They wrote one temp
file per version and ran in parallel, so each test now gets its own.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-09-28 10:16:19 +03:00
1 parent 8834d77d12
commit 8c9b485b6c
1 file changed
+11 -37
+11 -37
View File
@@ -757,8 +757,6 @@ pub fn load_bytes(name: &str, bytes: Vec<u8>) -> Result<CadDocument, String> {
let mut doc = DwgReader::from_stream(Cursor::new(bytes))
.read()
.map_err(|e| e.to_string())?;
let version = doc.version;
fix_pre_r2000_layer_plot_flags(&mut doc, version);
fix_viewport_status_flags(&mut doc);
fix_current_style_names(&mut doc);
Ok(doc)
@@ -1029,10 +1027,6 @@ fn finalize_loaded_outcome(
mut outcome: codec::ReadOutcome,
) -> Result<codec::ReadOutcome, String> {
let doc = &mut outcome.document;
if outcome.stats.source_format == Some(codec::SourceFormat::Dwg) {
let version = doc.version;
fix_pre_r2000_layer_plot_flags(doc, version);
}
normalize_block_origins(doc);
normalize_knotless_splines(doc);
if outcome.stats.source_format == Some(codec::SourceFormat::Dxf) {
@@ -2394,31 +2388,6 @@ pub fn purge_corrupt_entities(doc: &mut CadDocument) -> usize {
n
}
/// An R13 / R14 drawing cannot mark a layer as "don't plot" — the LAYER
/// record only carries frozen, off, frozen-in-new-viewport and locked as four
/// separate bits. The plot flag (and the lineweight, in the same packed
/// bit-short) arrived with R2000, so the reader has no bit to read for the
/// older versions and leaves the field at the `false` it starts from.
///
/// That default then marks every layer of such a drawing as "don't plot":
/// display and plot visibility are separate flags, so the drawing looked right
/// on screen while PLOT, the plot preview and QUICKPRINT all rendered a blank
/// page. What the older format means by default is what a freshly created
/// layer gets — `is_plottable: true` — so restore it here.
fn fix_pre_r2000_layer_plot_flags(doc: &mut CadDocument, version: codec::types::DxfVersion) {
use codec::types::DxfVersion;
// AC1012 is R13 and AC1014 is R14, the two versions with the four-bit LAYER
// record. From AC1015 (R2000) on, the file's own flag is authoritative and
// is read, so nothing is touched there. `Unknown` is left alone too: a
// version that could not be identified is the wrong thing to reason from.
if !matches!(version, DxfVersion::AC1012 | DxfVersion::AC1014) {
return;
}
for layer in doc.layers.iter_mut() {
layer.is_plottable = true;
}
}
/// opencadcodec's ViewportStatusFlags::from_bits() maps bit 0 → is_on and bit 15 → locked,
/// but the real DXF/DWG spec uses bit 15 (0x8000) → viewport on and bit 14 (0x4000) → locked.
/// Files from AutoCAD and other tools always set bit 15 for active viewports, leaving bit 0
@@ -2943,8 +2912,13 @@ mod pre_r2000_layer_plot_tests {
doc
}
fn saved_path(version: DxfVersion) -> std::path::PathBuf {
std::env::temp_dir().join(format!("ocs_plotflag_{}.dwg", version.as_str()))
/// Tests run in parallel, so each gets its own file.
fn saved_path(test: &str, version: DxfVersion) -> std::path::PathBuf {
std::env::temp_dir().join(format!(
"ocs_plotflag_{test}_{}_{}.dwg",
version.as_str(),
std::process::id()
))
}
/// The LAYER record only grew a plot flag in R2000. Reading an R14 drawing
@@ -2955,7 +2929,7 @@ mod pre_r2000_layer_plot_tests {
#[test]
fn an_r14_drawing_reads_back_with_every_layer_plottable() {
let doc = drawing_with_layers();
let path = saved_path(DxfVersion::AC1014);
let path = saved_path("r14_bytes", DxfVersion::AC1014);
save_as_version(&doc, &path, DxfVersion::AC1014).expect("save R14 DWG");
let bytes = std::fs::read(&path).expect("read R14 DWG");
let _ = std::fs::remove_file(&path);
@@ -2981,7 +2955,7 @@ mod pre_r2000_layer_plot_tests {
#[test]
fn an_r13_drawing_reads_back_with_every_layer_plottable() {
let doc = drawing_with_layers();
let path = saved_path(DxfVersion::AC1012);
let path = saved_path("r13_path", DxfVersion::AC1012);
save_as_version(&doc, &path, DxfVersion::AC1012).expect("save R13 DWG");
let loaded = load_file(&path).expect("load R13 DWG");
let _ = std::fs::remove_file(&path);
@@ -2997,7 +2971,7 @@ mod pre_r2000_layer_plot_tests {
fn a_modern_drawing_keeps_the_plot_flag_it_stored() {
let mut doc = drawing_with_layers();
doc.layers.get_mut("FINE").unwrap().is_plottable = false;
let path = saved_path(DxfVersion::AC1032);
let path = saved_path("modern", DxfVersion::AC1032);
save_as_version(&doc, &path, DxfVersion::AC1032).expect("save R2018 DWG");
let loaded = load_file(&path).expect("load R2018 DWG");
let _ = std::fs::remove_file(&path);
@@ -3025,7 +2999,7 @@ mod pre_r2000_layer_plot_tests {
line.common.layer = layer.to_string();
doc.add_entity(EntityType::Line(line)).expect("add line");
}
let path = saved_path(DxfVersion::AC1014);
let path = saved_path("r14_wires", DxfVersion::AC1014);
save_as_version(&doc, &path, DxfVersion::AC1014).expect("save R14 DWG");
let bytes = std::fs::read(&path).expect("read R14 DWG");
let _ = std::fs::remove_file(&path);