From 6cafea92bcc3a3b514edf9484eb8faab2dd8f30f Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Tue, 11 Aug 2026 17:16:46 +0300 Subject: [PATCH] fix(web): preserve DWG render state Carry rendering fields omitted by document serialization and normalize block origins before building web caches. --- Cargo.lock | 1 + crates/ocs_web_worker/Cargo.toml | 1 + crates/ocs_web_worker/src/lib.rs | 50 +++++++++++++++++++++++++++++- src/io/mod.rs | 1 + src/io/web_worker.rs | 53 ++++++++++++++++++++++++++++++-- web/ocs-parse-worker.js | 4 +-- 6 files changed, 104 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49537864..cb584ac0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3769,6 +3769,7 @@ dependencies = [ "console_error_panic_hook", "getrandom 0.3.4", "js-sys", + "serde", "sha2 0.10.9", "wasm-bindgen", ] diff --git a/crates/ocs_web_worker/Cargo.toml b/crates/ocs_web_worker/Cargo.toml index 015a8c4e..a91fb837 100644 --- a/crates/ocs_web_worker/Cargo.toml +++ b/crates/ocs_web_worker/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["cdylib"] [dependencies] acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "7e2fa8c", features = ["serde"] } bincode = "1.3" +serde = { version = "1", features = ["derive"] } console_error_panic_hook = "0.1" getrandom = { version = "0.3", features = ["wasm_js"] } js-sys = "0.3" diff --git a/crates/ocs_web_worker/src/lib.rs b/crates/ocs_web_worker/src/lib.rs index 5845100b..a3593b95 100644 --- a/crates/ocs_web_worker/src/lib.rs +++ b/crates/ocs_web_worker/src/lib.rs @@ -8,7 +8,23 @@ use sha2::{Digest, Sha256}; use wasm_bindgen::prelude::*; const HASH_MARKER: &str = "\nreport-source-sha256:"; -const PROTOCOL_VERSION: u16 = 3; +const PROTOCOL_VERSION: u16 = 4; + +#[derive(serde::Serialize)] +struct EntityRuntimeFields { + handle: u64, + linetype_handle: Option, + color_book_handle: Option, + face_visual_style_handle: Option, + edge_visual_style_handle: Option, + material_flags: u8, + material_handle: Option, + shadow_flags: u8, + plotstyle_flags: u8, + plotstyle_handle: Option, + entity_mode: Option, + has_ds_data: bool, +} /// Parse DWG/DXF on a dedicated browser worker and return a compact serialized /// document. The main wasm instance only deserializes and installs it, so the @@ -159,11 +175,43 @@ fn encode_result( recoverable_parse_error: bool, bytes: &[u8], ) -> Result { + let runtime_fields = result + .as_ref() + .ok() + .map(|outcome| { + outcome + .document + .entities() + .map(|entity| { + let common = entity.common(); + EntityRuntimeFields { + handle: common.handle.value(), + linetype_handle: common.linetype_handle.map(|handle| handle.value()), + color_book_handle: common.color_book_handle.map(|handle| handle.value()), + face_visual_style_handle: common + .face_visual_style_handle + .map(|handle| handle.value()), + edge_visual_style_handle: common + .edge_visual_style_handle + .map(|handle| handle.value()), + material_flags: common.material_flags, + material_handle: common.material_handle.map(|handle| handle.value()), + shadow_flags: common.shadow_flags, + plotstyle_flags: common.plotstyle_flags, + plotstyle_handle: common.plotstyle_handle.map(|handle| handle.value()), + entity_mode: common.entity_mode, + has_ds_data: common.has_ds_data, + } + }) + .collect::>() + }) + .unwrap_or_default(); let encoded = bincode::serialize(&( PROTOCOL_VERSION, result, source_sha256, recoverable_parse_error, + runtime_fields, )) .map_err(|error| worker_error(error.to_string(), bytes, true))?; Ok(Uint8Array::from(encoded.as_slice())) diff --git a/src/io/mod.rs b/src/io/mod.rs index 693a04e3..51a5443c 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -663,6 +663,7 @@ async fn load_web_bytes( merge_read_diagnostics(&mut outcome.stats, initial_stats); } let mut doc = outcome.document; + normalize_block_origins(&mut doc); if name.to_ascii_lowercase().ends_with(".dxf") { fix_dxf_dimension_rotations(&mut doc); fix_dxf_layout_plot_settings(&mut doc); diff --git a/src/io/web_worker.rs b/src/io/web_worker.rs index 8df85005..2a16a884 100644 --- a/src/io/web_worker.rs +++ b/src/io/web_worker.rs @@ -7,8 +7,24 @@ use wasm_bindgen::{JsCast, JsValue}; use web_sys::{ErrorEvent, MessageEvent, Worker, WorkerOptions, WorkerType}; const HASH_MARKER: &str = "\nreport-source-sha256:"; -const PROTOCOL_VERSION: u16 = 3; -const WORKER_URL: &str = "ocs-parse-worker.js?v=3"; +const PROTOCOL_VERSION: u16 = 4; +const WORKER_URL: &str = "ocs-parse-worker.js?v=4"; + +#[derive(serde::Deserialize)] +struct EntityRuntimeFields { + handle: u64, + linetype_handle: Option, + color_book_handle: Option, + face_visual_style_handle: Option, + edge_visual_style_handle: Option, + material_flags: u8, + material_handle: Option, + shadow_flags: u8, + plotstyle_flags: u8, + plotstyle_handle: Option, + entity_mode: Option, + has_ds_data: bool, +} pub(super) async fn parse_document( name: &str, @@ -45,6 +61,7 @@ pub(super) async fn parse_document( >, Option, bool, + Vec, ) = bincode::deserialize(&bytes) .map_err(|error| super::OpenLoadError::from(error.to_string()))?; if payload.0 != PROTOCOL_VERSION { @@ -54,7 +71,13 @@ pub(super) async fn parse_document( ))); } match payload.1 { - Ok(outcome) => Ok((outcome, payload.2)), + Ok(mut outcome) => { + restore_entity_runtime_fields( + &mut outcome.document, + payload.4, + ); + Ok((outcome, payload.2)) + } Err((message, read_stats)) => Err(super::OpenLoadError { message, source_sha256: payload.2, @@ -119,6 +142,30 @@ pub(super) async fn parse_document( result } +fn restore_entity_runtime_fields( + document: &mut acadrust::CadDocument, + fields: Vec, +) { + let handle = |value: Option| value.map(acadrust::Handle::new); + for fields in fields { + let Some(entity) = document.get_entity_mut(acadrust::Handle::new(fields.handle)) else { + continue; + }; + let common = entity.common_mut(); + common.linetype_handle = handle(fields.linetype_handle); + common.color_book_handle = handle(fields.color_book_handle); + common.face_visual_style_handle = handle(fields.face_visual_style_handle); + common.edge_visual_style_handle = handle(fields.edge_visual_style_handle); + common.material_flags = fields.material_flags; + common.material_handle = handle(fields.material_handle); + common.shadow_flags = fields.shadow_flags; + common.plotstyle_flags = fields.plotstyle_flags; + common.plotstyle_handle = handle(fields.plotstyle_handle); + common.entity_mode = fields.entity_mode; + common.has_ds_data = fields.has_ds_data; + } +} + pub(super) async fn sha256_document(bytes: &[u8]) -> Result { let options = WorkerOptions::new(); options.set_type(WorkerType::Module); diff --git a/web/ocs-parse-worker.js b/web/ocs-parse-worker.js index 5eb06381..ab347aff 100644 --- a/web/ocs-parse-worker.js +++ b/web/ocs-parse-worker.js @@ -1,7 +1,7 @@ -import init, { parse_document, sha256_document } from "./worker_pkg/ocs_web_worker.js?v=3"; +import init, { parse_document, sha256_document } from "./worker_pkg/ocs_web_worker.js?v=4"; const ready = init( - new URL("./worker_pkg/ocs_web_worker_bg.wasm?v=3", import.meta.url), + new URL("./worker_pkg/ocs_web_worker_bg.wasm?v=4", import.meta.url), ); self.onmessage = async ({ data }) => {