forked from 1b-agent/opencadstudio-upstream
fix: close the review findings on the issue wave
Two reviewers over the #1345/#1348/#1349 wave; no blockers, two majors, several minors — all fixed. - La16 was still billed at 4 B/px: the no-conversion special case keyed on native_bpp == 4, which La16 also is — but only Rgba8 is a real move in into_rgba8, so La16's decode peak is 8. The case now keys on the color type, and a table test pins every layout's peak (plus GIF's screen+frame 8) so the accounting can't silently drift. - A control-routed open of a damaged-but-recoverable drawing parked the operation behind the RecoveryPrompt modal (hang until the JS timeout, silent drop if another op arrived, or false success when a human declined). The open op now settles as failed with recovery_required and the parse error; the prompt stays for humans, automation can retry through the recovery flow. - json_values_match: integers beyond f64 precision compared by value (a u64 could round-trip-match a float); integral pairs now compare exactly and mixed integer/float matches only when the float is whole and equals the integer. - A queued web open settles with the explicit queued marker whenever the open slot was busy (the old name check made same-named in-flight opens look completed with an empty result). - ocs-control.js resolves with the API object reference, not window.ocsControl (undefined if the bridge already existed when the script ran); DATALINK on web says the typed path is superseded by the picker instead of silently discarding it; the wipeout depth test probes past the page background's rectangle; and the plot-path doc comment names the function it actually mirrors.
This commit is contained in:
1 parent
2c38de53e2
commit
d719fb7778
30 files changed
+143
-18
No files matched your search
@@ -3591,6 +3591,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = يجري فتح مناقشات OCS للمساعدة والأسئلة...
|
||||
.opening-ocs-web = يجري فتح OCS Web...
|
||||
.opening-the-command-reference = فتح مرجع الأوامر...
|
||||
.browser-cannot-open-typed-path = لا يستطيع المتصفح فتح مسار مكتوب؛ اختر الملف بدلاً من ذلك.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" محمّل بالفعل بمحتوى مختلف؛ تم الاحتفاظ بالملف الموجود.
|
||||
.opening-patreon-page = يجري فتح صفحة Patreon...
|
||||
.opening-feedback-page = يجري فتح صفحة الملاحظات...
|
||||
|
||||
@@ -3578,6 +3578,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Отваряне на OCS дискусии за помощ и въпроси...
|
||||
.opening-ocs-web = Отваряне на OCS уебсайта...
|
||||
.opening-the-command-reference = Отваряне на справочника за команди...
|
||||
.browser-cannot-open-typed-path = Браузърът не може да отвори въведен път; изберете файла.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" вече е зареден с различно съдържание; съществуващият файл е запазен.
|
||||
.opening-patreon-page = Отваряне на страницата в Patreon...
|
||||
.opening-feedback-page = Отваряне на страницата за обратна връзка...
|
||||
|
||||
@@ -3576,6 +3576,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Otevírání diskuzí OCS pro nápovědu a dotazy...
|
||||
.opening-ocs-web = Otevírání webu OCS...
|
||||
.opening-the-command-reference = Otevírání referenční příručky příkazů...
|
||||
.browser-cannot-open-typed-path = Prohlížeč nemůže otevřít zadanou cestu; vyberte soubor.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" je již načten s jiným obsahem; existující soubor byl zachován.
|
||||
.opening-patreon-page = Otevírání stránky Patreon...
|
||||
.opening-feedback-page = Otevírá se stránka zpětné vazby...
|
||||
|
||||
@@ -3577,6 +3577,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Eröffnung OCS Diskussionen für Hilfe und Fragen...
|
||||
.opening-ocs-web = Öffnen OCS Web...
|
||||
.opening-the-command-reference = Öffnen der Befehlsreferenz...
|
||||
.browser-cannot-open-typed-path = Der Browser kann einen eingegebenen Pfad nicht öffnen; wähle die Datei.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" ist bereits mit anderem Inhalt geladen; die vorhandene Datei wurde behalten.
|
||||
.opening-patreon-page = Eröffnungsseite Patreon...
|
||||
.opening-feedback-page = Feedbackseite öffnen...
|
||||
|
||||
@@ -3573,6 +3573,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Άνοιγμα των συζητήσεων OCS για βοήθεια και ερωτήσεις...
|
||||
.opening-ocs-web = Άνοιγμα του OCS Web...
|
||||
.opening-the-command-reference = Άνοιγμα της αναφοράς εντολών...
|
||||
.browser-cannot-open-typed-path = Ο browser δεν μπορεί να ανοίξει πληκτρολογημένη διαδρομή· διάλεξε το αρχείο.
|
||||
.already-loaded-different-contents-kept = Το "__ocs_fmt_0__" είναι ήδη φορτωμένο με διαφορετικό περιεχόμενο· διατηρήθηκε το υπάρχον αρχείο.
|
||||
.opening-patreon-page = Άνοιγμα της σελίδας Patreon...
|
||||
.opening-feedback-page = Άνοιγμα της σελίδας σχολίων...
|
||||
|
||||
@@ -3574,6 +3574,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Opening OCS Discussions for help and questions...
|
||||
.opening-ocs-web = Opening OCS Web...
|
||||
.opening-the-command-reference = Opening the command reference...
|
||||
.browser-cannot-open-typed-path = The browser cannot open a typed path; pick the file instead.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" is already loaded with different contents; the existing file was kept.
|
||||
.opening-patreon-page = Opening Patreon page...
|
||||
.opening-feedback-page = Opening feedback page...
|
||||
|
||||
@@ -3579,6 +3579,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Abriendo Debates de OCS para obtener ayuda y hacer preguntas...
|
||||
.opening-ocs-web = Abriendo OCS Web...
|
||||
.opening-the-command-reference = Abriendo la referencia de comandos...
|
||||
.browser-cannot-open-typed-path = El navegador no puede abrir una ruta escrita; elige el archivo.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" ya está cargado con contenido diferente; se conservó el archivo existente.
|
||||
.opening-patreon-page = Abriendo la página de Patreon...
|
||||
.opening-feedback-page = Abriendo la página de comentarios...
|
||||
|
||||
@@ -3578,6 +3578,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = OCS-keskustelujen avaaminen apua ja kysymyksiä varten...
|
||||
.opening-ocs-web = Avataan OCS Web...
|
||||
.opening-the-command-reference = Avataan komentoviittausta...
|
||||
.browser-cannot-open-typed-path = Selain ei voi avata kirjoitettua polkua; valitse tiedosto.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" on jo ladattu eri sisällöllä; olemassa oleva tiedosto säilytettiin.
|
||||
.opening-patreon-page = Avataan Patreon-sivua...
|
||||
.opening-feedback-page = Palautesivua avataan...
|
||||
|
||||
@@ -3579,6 +3579,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Ouverture OCS Discussions pour l'aide et les questions...
|
||||
.opening-ocs-web = Ouverture du site Web OCS...
|
||||
.opening-the-command-reference = Ouverture de la référence des commandes...
|
||||
.browser-cannot-open-typed-path = Le navigateur ne peut pas ouvrir un chemin saisi ; choisissez le fichier.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" est déjà chargé avec un contenu différent ; le fichier existant a été conservé.
|
||||
.opening-patreon-page = Ouverture de la page Patreon...
|
||||
.opening-feedback-page = Ouverture de la page de rétroaction...
|
||||
|
||||
@@ -3567,6 +3567,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = OCS मदद और प्रश्नों के लिए चर्चा खोलना।
|
||||
.opening-ocs-web = OCS वेब खोलना ...
|
||||
.opening-the-command-reference = कमांड संदर्भ खोला जा रहा है...
|
||||
.browser-cannot-open-typed-path = ब्राउज़र टाइप किए गए पथ को नहीं खोल सकता; इसके बजाय फ़ाइल चुनें।
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" अलग सामग्री के साथ पहले से लोड है; मौजूदा फ़ाइल रखी गई।
|
||||
.opening-patreon-page = Patreon पृष्ठ खोला जा रहा है…
|
||||
.opening-feedback-page = प्रतिक्रिया पृष्ठ खोलना
|
||||
|
||||
@@ -3578,6 +3578,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = A OCS beszélgetések megnyitása segítségért és kérdésekért...
|
||||
.opening-ocs-web = A OCS web megnyitása...
|
||||
.opening-the-command-reference = A parancsreferencia megnyitása...
|
||||
.browser-cannot-open-typed-path = A böngésző nem nyithat meg beírt útvonalat; válaszd a fájlt.
|
||||
.already-loaded-different-contents-kept = A(z) "__ocs_fmt_0__" már betöltve eltérő tartalommal; a meglévő fájl megőrizve.
|
||||
.opening-patreon-page = Patreon oldal megnyitása...
|
||||
.opening-feedback-page = Visszajelzési oldal megnyitása...
|
||||
|
||||
@@ -3578,6 +3578,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Apertura delle discussioni OCS per assistenza e domande...
|
||||
.opening-ocs-web = Apertura del Web OCS...
|
||||
.opening-the-command-reference = Apertura del riferimento dei comandi...
|
||||
.browser-cannot-open-typed-path = Il browser non può aprire un percorso digitato; scegli il file.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" è già caricato con contenuti diversi; il file esistente è stato mantenuto.
|
||||
.opening-patreon-page = Apertura della pagina Patreon...
|
||||
.opening-feedback-page = Apertura della pagina di feedback...
|
||||
|
||||
@@ -3567,6 +3567,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = ヘルプと質問のため OCS ディスカッションを開いています...
|
||||
.opening-ocs-web = OCS Web を開いています...
|
||||
.opening-the-command-reference = コマンドリファレンスを開いています...
|
||||
.browser-cannot-open-typed-path = ブラウザは入力されたパスを開けません。ファイルを選択してください。
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" は既に別の内容で読み込まれています。既存のファイルを保持しました。
|
||||
.opening-patreon-page = Patreon ページを開いています...
|
||||
.opening-feedback-page = フィードバックページを開いています...
|
||||
|
||||
@@ -3578,6 +3578,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = OCS 열기 도움말 및 질문에 대한 토론...
|
||||
.opening-ocs-web = OCS 웹을 여는 중...
|
||||
.opening-the-command-reference = 명령 참조 열기...
|
||||
.browser-cannot-open-typed-path = 브라우저는 입력한 경로를 열 수 없습니다. 파일을 선택하세요.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__"이(가) 이미 다른 내용으로 로드되었습니다. 기존 파일을 유지했습니다.
|
||||
.opening-patreon-page = Patreon 페이지를 여는 중...
|
||||
.opening-feedback-page = 피드백 페이지를 여는 중...
|
||||
|
||||
@@ -3577,6 +3577,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Openen OCS Discussie voor hulp en vragen...
|
||||
.opening-ocs-web = Openen OCS Web...
|
||||
.opening-the-command-reference = Commandoreferentie openen...
|
||||
.browser-cannot-open-typed-path = De browser kan een getypt pad niet openen; kies het bestand.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" is al geladen met andere inhoud; het bestaande bestand is bewaard.
|
||||
.opening-patreon-page = Patreon pagina openen...
|
||||
.opening-feedback-page = Herinneringspagina openen...
|
||||
|
||||
@@ -3578,6 +3578,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Otwieranie dyskusji OCS w celu uzyskania pomocy i pytań...
|
||||
.opening-ocs-web = Otwieranie OCS Web...
|
||||
.opening-the-command-reference = Otwieranie dokumentacji poleceń...
|
||||
.browser-cannot-open-typed-path = Przeglądarka nie otworzy wpisanej ścieżki; wybierz plik.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" jest już wczytany z inną zawartością; zachowano istniejący plik.
|
||||
.opening-patreon-page = Otwieranie strony Patreon...
|
||||
.opening-feedback-page = Otwieram stronę z opiniami...
|
||||
|
||||
@@ -3579,6 +3579,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Abrindo Discussões do OCS para ajuda e perguntas...
|
||||
.opening-ocs-web = Abrindo OCS Web...
|
||||
.opening-the-command-reference = Abrindo a referência de comandos...
|
||||
.browser-cannot-open-typed-path = O navegador não pode abrir um caminho digitado; escolha o ficheiro.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" já está carregado com conteúdo diferente; o ficheiro existente foi mantido.
|
||||
.opening-patreon-page = Abrindo página do Patreon...
|
||||
.opening-feedback-page = Abrindo página de comentários...
|
||||
|
||||
@@ -3580,6 +3580,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Открытие OCS Дискуссии о помощи и вопросах
|
||||
.opening-ocs-web = Открытие OCS Веб-сайт
|
||||
.opening-the-command-reference = Открытие справочника команд...
|
||||
.browser-cannot-open-typed-path = Браузер не может открыть введённый путь; выберите файл.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" уже загружен с другим содержимым; существующий файл сохранён.
|
||||
.opening-patreon-page = Открытие страницы Patreon...
|
||||
.opening-feedback-page = Открываем страницу обратной связи...
|
||||
|
||||
@@ -3529,6 +3529,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = Yardım ve sorular için OCS Tartışmaları açılıyor...
|
||||
.opening-ocs-web = OCS Web açılıyor...
|
||||
.opening-the-command-reference = Komut başvurusu açılıyor...
|
||||
.browser-cannot-open-typed-path = Tarayıcı yazılan bir yolu açamaz; dosyayı seçin.
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__" zaten farklı içerikle yüklü; mevcut dosya tutuldu.
|
||||
.opening-patreon-page = Patreon sayfası açılıyor...
|
||||
.opening-feedback-page = Geri bildirim sayfası açılıyor...
|
||||
|
||||
@@ -3562,6 +3562,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = 开幕OCS 讨论帮助和问题...
|
||||
.opening-ocs-web = 打开OCS网络...
|
||||
.opening-the-command-reference = 正在打开命令参考...
|
||||
.browser-cannot-open-typed-path = 浏览器无法打开键入的路径;请改为选择文件。
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__"已以不同内容加载;保留了现有文件。
|
||||
.opening-patreon-page = 打开帕特伦的页面...
|
||||
.opening-feedback-page = 打开反馈页面...
|
||||
|
||||
@@ -3574,6 +3574,7 @@ view =
|
||||
.opening-ocs-discussions-for-help-and-questions = 開幕OCS 討論幫助和問題...
|
||||
.opening-ocs-web = 開啟OCS網路...
|
||||
.opening-the-command-reference = 正在開啟命令參考...
|
||||
.browser-cannot-open-typed-path = 瀏覽器無法開啟輸入的路徑;請改為選擇檔案。
|
||||
.already-loaded-different-contents-kept = "__ocs_fmt_0__"已以不同內容載入;保留了現有檔案。
|
||||
.opening-patreon-page = 開啟帕特倫的頁面...
|
||||
.opening-feedback-page = 開啟反饋頁面...
|
||||
|
||||
@@ -1601,7 +1601,16 @@ impl OpenCADStudio {
|
||||
// then runs from `DataLinkCsvPicked`.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
let _ = path;
|
||||
// Say the typed argument is superseded — a silent
|
||||
// redirect looks like the input was lost.
|
||||
if !path.trim().is_empty() {
|
||||
self.command_line.push_info(
|
||||
crate::t!(
|
||||
"The browser cannot open a typed path; pick the file instead."
|
||||
)
|
||||
.as_ref(),
|
||||
);
|
||||
}
|
||||
return Some(Task::perform(
|
||||
crate::io::pick_datalink_csv_web(),
|
||||
Message::DataLinkCsvPicked,
|
||||
|
||||
@@ -755,9 +755,13 @@ impl OpenCADStudio {
|
||||
// stays pending until the open settles instead of
|
||||
// completing before the drawing exists.
|
||||
let task = self.update(Message::PollWebControl);
|
||||
if self.opening.as_ref().is_none_or(|opening| opening.name != name) {
|
||||
// Another open holds the slot; the poll opens this
|
||||
// entry once it frees, after this operation settles.
|
||||
// Another open holds the slot; the poll opens this entry
|
||||
// once it frees, after this operation settles. Report
|
||||
// `queued` whenever the slot was busy at submit — the
|
||||
// name check skipped same-named in-flight opens, making
|
||||
// the op look completed with an empty result before the
|
||||
// queued entry had opened.
|
||||
if self.opening.is_some() {
|
||||
self.set_control_result(json!({"queued": true, "name": name}));
|
||||
}
|
||||
return Ok(task);
|
||||
|
||||
+21
-5
@@ -1111,11 +1111,27 @@ fn requested_handle(request: &Value) -> Result<acadrust::Handle, String> {
|
||||
/// bools and null stay exact; objects and arrays recurse.
|
||||
fn json_values_match(stored: &Value, expected: &Value) -> bool {
|
||||
match (stored, expected) {
|
||||
(Value::Number(stored), Value::Number(expected)) => match (stored.as_f64(), expected.as_f64()) {
|
||||
(Some(stored), Some(expected)) => stored == expected,
|
||||
// Out-of-range or arbitrary-precision numbers keep exact equality.
|
||||
_ => stored == expected,
|
||||
},
|
||||
(Value::Number(stored), Value::Number(expected)) => {
|
||||
// Integers compare exactly (a u64 beyond f64 precision must not
|
||||
// round-trip-match a float); mixed integer/float matches only
|
||||
// when the float is whole and equals the integer.
|
||||
match (stored.as_u64(), expected.as_u64()) {
|
||||
(Some(stored), Some(expected)) => stored == expected,
|
||||
(Some(stored), None) => match expected.as_f64() {
|
||||
Some(expected) => expected.fract() == 0.0 && expected >= 0.0 && stored as f64 == expected,
|
||||
None => false,
|
||||
},
|
||||
(None, Some(expected)) => match stored.as_f64() {
|
||||
Some(stored) => stored.fract() == 0.0 && stored >= 0.0 && expected as f64 == stored,
|
||||
None => false,
|
||||
},
|
||||
_ => match (stored.as_i64(), expected.as_i64(), stored.as_f64(), expected.as_f64()) {
|
||||
(Some(stored), Some(expected), _, _) => stored == expected,
|
||||
(_, _, Some(stored), Some(expected)) => stored == expected,
|
||||
_ => stored == expected,
|
||||
},
|
||||
}
|
||||
}
|
||||
(Value::Object(stored), Value::Object(expected)) => {
|
||||
stored.len() == expected.len()
|
||||
&& stored.iter().all(|(key, value)| {
|
||||
|
||||
+25
-1
@@ -1059,9 +1059,33 @@ impl OpenCADStudio {
|
||||
}
|
||||
if e.recovery_available {
|
||||
if let Some(opening) = self.opening.as_mut() {
|
||||
opening.recovery_error = Some(e.message);
|
||||
let recovery_message = e.message.clone();
|
||||
opening.recovery_error = Some(recovery_message.clone());
|
||||
opening.recovery_read_stats = e.read_stats;
|
||||
self.active_modal = Some(super::ModalKind::RecoveryPrompt);
|
||||
// A control-routed open (automation) must not park
|
||||
// behind a modal nobody may answer: settle the
|
||||
// operation as failed with the parse error. The
|
||||
// prompt stays for a human; automation retries with
|
||||
// the recovery op if it wants the content.
|
||||
// A control-routed open (automation) must not park
|
||||
// behind a modal nobody may answer: settle the
|
||||
// operation as failed with the parse error. The
|
||||
// prompt stays for a human; automation can retry
|
||||
// through the recovery flow if it wants the content.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
let settled = serde_json::json!({
|
||||
"ok": false,
|
||||
"status": "failed",
|
||||
"code": "recovery_required",
|
||||
"error": format!(
|
||||
"the drawing is damaged and needs a recovery decision: {}",
|
||||
recovery_message
|
||||
),
|
||||
});
|
||||
self.set_control_result(settled);
|
||||
}
|
||||
return Task::none();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2597,11 +2597,18 @@ mod tests {
|
||||
"tied wipeout must mask the wire: {black} !< {last_wipe}"
|
||||
);
|
||||
// Below the wire (DRAWORDER under): depth wins and the wire paints
|
||||
// back on top of the mask.
|
||||
// back on top of the mask. The page BACKGROUND is also a white
|
||||
// rectangle: skip past its `re` operator so the probe cannot
|
||||
// accidentally measure the background if a future serializer
|
||||
// paints it.
|
||||
let mut page = test_page(vec![line_wire("70040", 0.0, BLACK)]);
|
||||
page.content.wipeouts = vec![wipeout(-0.5)];
|
||||
let stream = render_stream(page);
|
||||
let wipe = fill_op_pos(&stream, "1 1 1 rg", 0);
|
||||
let background = stream
|
||||
.windows(2)
|
||||
.position(|w| w == b"re")
|
||||
.expect("the page background rectangle serializes");
|
||||
let wipe = fill_op_pos(&stream, "1 1 1 rg", background);
|
||||
let black = stroke_op_pos(&stream, "0 0 0 RG", 0);
|
||||
assert!(
|
||||
wipe < black,
|
||||
|
||||
@@ -1887,6 +1887,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
|
||||
"Opening OCS Discussions for help and questions..." => Some(("view", "opening-ocs-discussions-for-help-and-questions")),
|
||||
"Opening OCS Web..." => Some(("view", "opening-ocs-web")),
|
||||
"Opening the command reference..." => Some(("view", "opening-the-command-reference")),
|
||||
"The browser cannot open a typed path; pick the file instead." => Some(("display", "browser-cannot-open-typed-path")),
|
||||
"\"{name}\" could not be sized from its header and decoding it exceeded the {limit} MB image limit of this build — it cannot be attached." => Some(("file", "image-refusal-unknown-size")),
|
||||
"\"{name}\" is already loaded with different contents; the existing file was kept." => Some(("view", "already-loaded-different-contents-kept")),
|
||||
"Opening Patreon page..." => Some(("view", "opening-patreon-page")),
|
||||
|
||||
@@ -665,9 +665,14 @@ fn native_footprint(format: Option<image::ImageFormat>, color: Option<image::Col
|
||||
_ => 4,
|
||||
});
|
||||
// `DynamicImage::into_rgba8` only MOVES for Rgba8; every other layout
|
||||
// allocates the RGBA destination while the native buffer is still
|
||||
// alive, so both coexist (image 0.25 buffer.rs cast_in_color_space).
|
||||
let peak_bpp = if native_bpp == 4 { 4 } else { native_bpp + 4 };
|
||||
// — including the 4 B/px La16 — allocates the RGBA destination while
|
||||
// the native buffer is still alive, so both coexist (image 0.25
|
||||
// buffer.rs cast_in_color_space).
|
||||
let peak_bpp = if matches!(color, Some(image::ColorType::Rgba8)) {
|
||||
4
|
||||
} else {
|
||||
native_bpp + 4
|
||||
};
|
||||
// GIF decodes the frame into its own buffer while the screen-sized
|
||||
// output buffer is live — two RGBA-sized allocations coexist.
|
||||
let peak_bpp = match format {
|
||||
@@ -1261,6 +1266,39 @@ pub use web_fetch::{
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// The decode peak per layout: into_rgba8 is a MOVE for Rgba8 only —
|
||||
/// every other layout pays native + RGBA coexisting. GIF additionally
|
||||
/// carries the screen-sized output beside a (clamped) frame buffer.
|
||||
#[test]
|
||||
fn native_footprint_peaks_match_the_coexistence_math() {
|
||||
use image::ColorType;
|
||||
let png = image::ImageFormat::Png;
|
||||
let gif = image::ImageFormat::Gif;
|
||||
let cases = [
|
||||
(ColorType::L8, 5u64),
|
||||
(ColorType::La8, 6),
|
||||
(ColorType::Rgb8, 7),
|
||||
(ColorType::Rgba8, 4),
|
||||
(ColorType::L16, 6),
|
||||
// 4 B/px but NOT a move — the La16 hole this test pins.
|
||||
(ColorType::La16, 8),
|
||||
(ColorType::Rgb16, 10),
|
||||
(ColorType::Rgba16, 12),
|
||||
(ColorType::Rgb32F, 16),
|
||||
(ColorType::Rgba32F, 20),
|
||||
];
|
||||
for (color, expected) in cases {
|
||||
assert_eq!(
|
||||
native_footprint(Some(png), Some(color)).peak_bpp,
|
||||
expected,
|
||||
"{color:?}"
|
||||
);
|
||||
}
|
||||
assert_eq!(native_footprint(Some(gif), Some(ColorType::Rgba8)).peak_bpp, 8);
|
||||
assert_eq!(native_footprint(None, None).peak_bpp, 8);
|
||||
}
|
||||
|
||||
|
||||
/// Encode a small deterministic PNG entirely in memory — the same codec
|
||||
/// `decode_from_memory` reads, so no fixture file is needed.
|
||||
fn png_bytes(w: u32, h: u32, tint: u8) -> Vec<u8> {
|
||||
|
||||
+1
-1
@@ -566,7 +566,7 @@ impl Scene {
|
||||
// canvas path re-reads the label per frame but this plot path used to
|
||||
// clone the stale value, so every top-level hatch exported at depth 0
|
||||
// and DRAWORDER (SORTENTS) never reached the PDF (#1345). Refresh the
|
||||
// per-entity label here exactly like `hatch_models_for_view`.
|
||||
// per-entity label here exactly like `synced_hatch_models`.
|
||||
let depths = self.draw_depth_map();
|
||||
for (&handle, model) in self.hatches.iter() {
|
||||
let Some(source) = self.document.get_entity(handle) else {
|
||||
|
||||
+7
-2
@@ -21,7 +21,10 @@
|
||||
let readyResolve;
|
||||
const ready = new Promise(resolve => { readyResolve = resolve; });
|
||||
const settle = () => {
|
||||
readyResolve(window.ocsControl);
|
||||
// apiObject is assigned to window.ocsControl at the END of this IIFE;
|
||||
// resolve with the local reference so a synchronous bridge (script
|
||||
// injected late) cannot settle `ready` with undefined.
|
||||
readyResolve(apiObject);
|
||||
window.dispatchEvent(new Event("ocs-ready"));
|
||||
};
|
||||
const poll = setInterval(() => {
|
||||
@@ -68,5 +71,7 @@
|
||||
return reply;
|
||||
}
|
||||
|
||||
window.ocsControl = {ready, request};
|
||||
const apiObject = {ready, request};
|
||||
|
||||
window.ocsControl = apiObject;
|
||||
})();
|
||||
Reference in new issue
Block a user