Sửa 3 lỗi edit inline vòng 2 (file thật Word-export): hết □ thay dấu cách, dòng không vỡ khi thêm ký tự, ô sửa WYSIWYG đúng cỡ từng dòng

Chẩn đoán □: PDFium FPDFText_LoadFont nạp LẠI font subset rồi SetText map
U+0020 ra .notdef (hộp vuông) dù cmap font CÓ glyph space (đã probe cả 2
subtable) — lỗi PDFium với font nạp động, không phải do font.

Engine (edit.rs):
- Tầng 0 mới của thang font reflow: DÙNG LẠI chính font object gốc trong
  PDF (PdfFontToken của run neo, không nạp lại) — glyph + charcode map gốc
  xử lý dấu cách chuẩn, file không phình; chỉ chọn sau khi PROBE ghi/đọc-lại
  toàn bộ text mới thành công (tạo object nháp → so text → gỡ + mem::forget)
- Ghi từng dòng xong ĐỌC LẠI NGAY tự kiểm; PDFium vẫn vứt ký tự → gỡ và ghi
  lại TỪNG TỪ tự đặt vị trí bằng advance hmtx (không bao giờ ghi glyph dấu
  cách) — lưới an toàn cuối cho font lạ
- Dòng cứng (\n từ ô sửa) NỞ tới +35% bề rộng khối (chặn mép trang) trước
  khi bẻ lại — hộp text tự nở như Foxit; khối căn giữa nở đều quanh tâm
- line_styles theo baseline gốc: dòng cứng thứ i giữ ĐÚNG CỠ dòng gốc thứ i
  (tiêu đề 22.5/20pt không bị ép cả khối về 1 cỡ)

UI (main.js + styles.css):
- Ô sửa cả đoạn đổi textarea → contenteditable plaintext-only: MỖI DÒNG GỐC
  = 1 div đúng font/cỡ/màu/đậm-nghiêng CỦA DÒNG ĐÓ, khối căn giữa hiện căn
  giữa (nở đều 2 phía quanh tâm), khung bù lệch dọc line-box → chữ trong ô
  TRÙNG vị trí chữ gốc khi mở; con trỏ đặt đúng điểm đúp (caretRangeFromPoint);
  Enter xuống dòng, Ctrl+Enter/blur áp dụng, Esc huỷ, dán luôn chữ thuần

Kiểm chứng file thật: "HỢP"→"HỢPP" giữ đúng 2 dòng căn giữa cỡ 22.5/20,
font BAAAAA+TimesNewRomanPS-BoldMT gốc, dấu cách nguyên vẹn, render khớp
bản gốc. Test: +2 hồi quy (giữ cỡ từng dòng; dòng nở không bẻ) → edit 21/21,
các suite annot/organize/redact/form xanh. Docs 12 (mục vá vòng 2), 13
(E39–E42).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgnbPwSoRGNH7LHsDUmRpk
This commit is contained in:
2026-07-16 16:15:04 +00:00
co-authored by Claude Fable 5
parent c8f22b091f
commit 58cba1f415
6 changed files with 500 additions and 96 deletions
+31 -1
View File
@@ -60,10 +60,40 @@ per-char xen run rỗng, cỡ 22.5pt + 20pt, bbox chữ có dấu tụt thấp):
chữ cũ; **phát hiện khối căn giữa** (tâm các dòng trùng tâm khối) → dòng mới
giữ căn giữa. 2 test hồi quy mới (nở indices, giữ căn giữa) — 19 test edit.
### Vá vòng 2 theo phản hồi file thật (□ thay dấu cách, vỡ dòng, ô sửa lệch)
Ba lỗi user báo sau khi thử bản build 6 trên chính file Word-export:
- **Dấu cách thành ô vuông □ sau khi lưu**: PDFium `FPDFText_LoadFont` nạp
LẠI font subset (Word xuất) rồi `SetText` sẽ map U+0020 ra `.notdef` (glyph
hộp) dù cmap của font CÓ space — lỗi nằm ở PDFium, không phải font. Fix:
**tầng 0 mới của thang font reflow — dùng LẠI chính font object gốc trong
PDF** (lấy `PdfFontToken` từ run neo, không nạp lại): glyph + charcode map
gốc xử lý dấu cách chuẩn, file không phình thêm bản font nữa. Chỉ chọn sau
khi **probe ghi/đọc-lại toàn bộ text mới** thành công (tạo object nháp →
so text → gỡ). Khi ghi từng dòng cũng **đọc lại ngay để tự kiểm** — nếu
PDFium vẫn âm thầm vứt ký tự thì gỡ và **ghi lại theo TỪNG TỪ tự đặt vị trí
bằng advance hmtx** (không bao giờ ghi glyph dấu cách) — lưới an toàn cuối.
- **Thêm 1 ký tự làm vỡ dòng** ("HỢP"→"HỢPP" đẩy "LOG" rơi xuống dòng mới):
dòng cứng (`\n` từ ô sửa) giờ được **NỞ tới +35% bề rộng khối** (chặn mép
trang) trước khi phải bẻ lại — hành vi hộp text tự nở của Foxit; khối căn
giữa nở đều 2 phía quanh tâm.
- **Mỗi dòng giữ đúng CỠ CHỮ GỐC của dòng đó** (tiêu đề 22.5/20pt không còn
bị ép cả khối về cỡ run neo): kế hoạch reflow ghi `line_styles` theo từng
baseline gốc, dòng cứng thứ i ăn cỡ dòng gốc thứ i.
- **Ô sửa WYSIWYG**: thay textarea bằng `contenteditable` — mỗi dòng gốc là
1 div với đúng **font/cỡ/màu/đậm-nghiêng CỦA DÒNG ĐÓ**, khối căn giữa hiện
căn giữa, khung đặt trùng bbox khối (bù lệch dọc line-box) → chữ trong ô
nằm NGUYÊN vị trí chữ gốc khi bắt đầu sửa; con trỏ đặt đúng chỗ vừa đúp
(`caretRangeFromPoint`).
- Kiểm chứng trên file thật: sửa "HỢP"→"HỢPP" giữ đúng 2 dòng căn giữa cỡ
22.5/20pt, font `BAAAAA+TimesNewRomanPS-BoldMT` gốc, dấu cách nguyên vẹn,
render so khớp bản gốc. 2 test hồi quy mới (`reflow_keeps_per_line_font_sizes`,
`reflow_hard_line_grows_without_rewrap`) — 21 test edit.
### Giới hạn ghi nhận (v1, sẽ nâng ở vòng sau)
- Đoạn justify (giãn đều 2 lề) reflow về căn trái; chưa kerning; khối text
XOAY chưa reflow theo hướng xoay (dòng mới đặt theo trục ngang).
- Khối lẫn NHIỀU font/cỡ trong 1 đoạn: dòng mới thống nhất theo run neo.
- Khối lẫn NHIỀU font/cỡ trong 1 ĐOẠN: cỡ giữ theo TỪNG DÒNG; font/màu theo
run neo (dòng lẫn nhiều font sẽ thống nhất font).
> Iteration 1: 43/43 test, đã chạy app thật + chụp ảnh xác minh.
+4
View File
@@ -49,6 +49,10 @@ cargo run
| E36 | Trong ô sửa: click chuột chỗ khác của đoạn để đổi vị trí con trỏ | Con trỏ di chuyển bình thường, **KHÔNG thoát edit** | |
| E37 | Sửa vài chữ rồi Ctrl+Enter | Chữ mới thay SẠCH chữ cũ (không chồng chữ), tiêu đề căn giữa **vẫn căn giữa** | |
| E38 | Khi ô sửa đang mở | Ô che kín chữ cũ bên dưới (không thấy 2 lớp chữ) | |
| E39 | Mở ô sửa trên tiêu đề 2 dòng 2 cỡ chữ (22.5/20pt) | Chữ trong ô hiện **đúng cỡ TỪNG DÒNG + căn giữa + đậm/màu như bản gốc**, vị trí chữ TRÙNG chữ gốc (không xê dịch khi bắt đầu sửa) | |
| E40 | Thêm 1–2 ký tự vào dòng dài nhất (vd "HỢP"→"HỢPP") rồi áp dụng | Dòng **NỞ ra, KHÔNG bị bẻ** thành dòng mới; số dòng giữ nguyên | |
| E41 | Sau khi áp dụng, nhìn khoảng trắng giữa các từ | Dấu cách bình thường — **KHÔNG có ô vuông □**; mở lại ở Foxit/Adobe font vẫn là font gốc của file | |
| E42 | Sửa tiêu đề rồi đo bằng mắt cỡ 2 dòng | Dòng 1 vẫn to hơn dòng 2 đúng như gốc (cỡ chữ giữ THEO DÒNG) | |
## Bổ sung — Đúp chuột vào chữ từ viewer thường (chuẩn Foxit Editor)
| # | Thao tác | Kỳ vọng | KQ |