Skip to content

fix(serializer/hwp): 편집으로 만든 글상자의 저장 워드에 글상자 비트 (#8172) - #8176

Closed
planet6897 wants to merge 1 commit into
edwardkim:develfrom
planet6897:fix/8172-textbox-shape-storage-bit
Closed

planet6897 wants to merge 1 commit into
edwardkim:develfrom
planet6897:fix/8172-textbox-shape-storage-bit

Conversation

@planet6897

Copy link
Copy Markdown
Contributor

변경 요약

편집 API createShapeControl로 만든 글상자(shapeType: 'textbox')를 HWP로 저장하면 한컴 2024가 손상 문서로 거부하던 문제를 고친다. studio의 글상자 그리기도 같은 경로를 쓴다.

  • 원인: create_shape_control_native가 도형 종류와 관계없이 SHAPE_COMPONENT 저장 워드(flip)를 0x0008_0000으로 두어 글상자 비트 0x0100_0000이 빠졌다. 이 비트만 바꾸면 한컴이 정상으로 여는 것은 이슈 #8172의 한 필드 교체 실험이 근거다.
  • 수정: DrawingObjAttr::sync_text_box_storage_bit()가 비트를 text_box 유무에 맞춘다. 글상자가 있으면 세우고, 없으면 지운다. hwpx_to_hwp가 지키는 계약(글상자 없는 도형에 세우면 한컴이 거부)과 같다.
    • 적용 경로: 글상자 생성(create_shape_control_native), 기존 도형에 글상자 붙이기·떼기(set_text_box_at)
    • 비적용 경로: HWPX/HWP3 → HWP 변환은 hwpx_to_hwp가 flip == 0일 때 이미 같은 값을 채운다. HWP 원본의 저장값은 그대로 보존한다.

관련 이슈

Closes #8172

테스트

  • 변경 범위: Rust (편집 command의 저장 속성)
  • 검증한 commit SHA / 정책 비교 PR base SHA: 6d20cb5353985492fcdd3340fc8c2ee699d9ed57 / def947c2149df5bc812d801e6e79be19a403b4d1
  • 실행 명령·결과:
항목 결과
cargo fmt --all -- --check 통과
native Clippy / WASM32 lib Clippy / workspace all-targets Clippy (-D warnings) 통과
cargo build --locked --workspace 통과
node scripts/rust-test-suite-manifest.mjs --check --base-ref def947c2149df5bc812d801e6e79be19a403b4d1 통과
cargo nextest run --workspace 11,479건 중 11,478 통과, 1 실패(아래), 45 skipped
새 회귀 tests/cases/issue_8172_textbox_shape_storage_bit.rs 3건 수정 전 3건 모두 실패(글상자=true flip=0x00080000), 수정 후 3건 통과

nextest 실패 1건 issue_6520_svg_layer_contract::subset_font_bytes_are_deterministic_for_multiple_codepoints(assertion failed: outputs[0].contains("data:font/opentype;base64,"))는 이 변경과 무관하다. 같은 host에서 이 커밋이 없는 base def947c21에서도 같은 assertion으로 실패한다. 이 host에는 한컴 글꼴 33개가 시스템에 설치되어 있어 글꼴 해석 환경 차이로 보이며, 이 PR은 SVG·글꼴 경로를 바꾸지 않는다.

회귀 3건:

  • created_textbox_carries_storage_bit_and_rectangle_does_not: 사각형과 글상자를 함께 만들고, 글상자에만 비트가 있으며 두 도형 모두 기본 비트 0x0008_0000을 유지하는지 확인한다.
  • storage_bit_survives_hwp_save_and_reopen: export_hwp_native·export_hwp_with_adapter_snapshot으로 저장하고 다시 연 뒤에도 비트와 글상자 수가 보존되는지 확인한다.
  • attaching_and_detaching_text_box_keeps_storage_bit_in_sync: 사각형에 글상자를 붙이면 비트가 서고 저장·재열기 후 유지되며, 떼면 비트가 지워지는지 확인한다.

한컴 2024 실측 (hwp2024Convert MCP, engine 2024, Print PDF):

수정본 입력 (createBlankDocument + createShapeControl, exportHwp) 저장 워드 한컴 2024
글상자 0x01080000 열림, 1쪽 출력
사각형 + 글상자 0x00080000 / 0x01080000 열림, 1쪽 출력
사각형 0x00080000 열림, 1쪽 출력
사각형에 글상자 붙이기 0x01080000 열림, 1쪽 출력

수정 전 글상자 입력의 거부(HANCOM_DOCUMENT_OPEN_REJECTED)는 이슈 본문에 기록되어 있다.

  • 조판 영향: 비해당. 바뀐 값은 SHAPE_COMPONENT 저장 워드뿐이다. renderer·layout·typeset은 이 워드(shape_attr.flip)를 읽지 않으므로(src/renderer, queries/rendering.rs 검색 결과 0건) 화면 출력과 쪽 배치는 바뀌지 않는다. 그래서 Visual Sweep·TSV는 실행하지 않았다.

  • #[cfg(test)] 변경 없음 → rust-unit-test-tiers --check 비해당

  • Studio 코드 변경 없음

  • 변경 범위별 필수 검증을 수행했고, 제출 HEAD가 검증한 commit과 같음을 확인

  • Rust 변경: fmt, native·WASM32·workspace all-target Clippy 통과

  • Rust 변경: focused 회귀와 전체 nextest 수행

  • 조판 영향 여부를 실제 소비 경로로 판단 (비해당, 위 근거)

  • 새 integration test 원본은 tests/cases/*.rs에만 추가했고 generated suite·manifest는 포함하지 않음

createShapeControl 이 도형 종류와 관계없이 SHAPE_COMPONENT 저장 워드를
0x0008_0000 으로 두어, 글상자 도형에 0x0100_0000 비트가 빠졌다. 한컴 2024 는
이 비트 없는 글상자 HWP 를 손상 문서로 거부한다.

DrawingObjAttr::sync_text_box_storage_bit 로 비트를 text_box 유무에 맞춘다.
글상자 생성(createShapeControl)과 기존 도형에 글상자 붙이기·떼기(set_text_box_at)
경로에 적용한다. 글상자 없는 도형에는 세우지 않는다(hwpx_to_hwp 와 같은 계약).

- 회귀: tests/cases/issue_8172_textbox_shape_storage_bit.rs 3건 — 수정 전 3건
  모두 flip=0x00080000 으로 실패, 수정 후 통과
- 한컴 2024(MCP engine 2024): 수정본 글상자·사각형+글상자·사각형·붙인 글상자
  HWP 4건 모두 열림, Print PDF 1쪽씩 출력
@jangster77

Copy link
Copy Markdown
Collaborator

@planet6897 #8148 로 planet6897 님의 기존 pr 의 리베이스가 필요합니다.
https://github.com/edwardkim/rhwp/pulls?q=is%3Apr+state%3Aopen+author%3Aplanet6897 먼저 리베이스 부탁드립니다.

#8173 참고 부탁드립니다.

@jangster77
jangster77 self-requested a review October 24, 2026 07:24
@edwardkim edwardkim added api 공개 API/JS·WASM 바인딩/스캔·편집 API 계약과 소비자 호환성 bug Something isn't working roundtrip parse→serialize→reparse 및 IR/render diff 기반 회귀 검증 serialization 문서 저장/직렬화: HWPX/HWP 출력, XML/OLE 속성 보존, roundtrip 저장 정합성 labels Oct 24, 2026 — with ChatGPT Codex Connector
@edwardkim edwardkim added this to the v1.0.0 milestone Oct 24, 2026 — with ChatGPT Codex Connector
jangster77 added a commit that referenced this pull request Oct 25, 2026
기존 planet6897 PR #8111·#8141·#8152·#8157·#8159·#8163·#8170·#8176·#8185·#8193의 기능 commit 49개와 통합 보정을 반영합니다. 중복 종료된 #8130의 임시 2개 적용은 제거했으며 기능 적용 수에서 제외합니다.

메인터너 보정은 현재 셀 글줄·물리 프레임·선언 행 높이와 선택 span 정렬의 일관성, 공백·출력 경계 및 요청한 회귀 제외를 처리합니다. sample16 계열과 행정업무운영 편람 HWP/HWPX는 사용자 지시로 검토에서 제외했습니다.

검증 code head 673c1d5f7cdcb5573b793ba2d2abaaedd2602134의 전체 nextest는 11,481 PASS/0 FAIL/45 skip이며 필수 로컬 게이트 14개를 통과했습니다. Native/fresh WASM 각35조건·2,041쪽의 최저 raw 91.87422%/91.82753%,90% 미달·고정 devel 대비0.1%p 이상 하락은 없습니다. 실제 Native15/Canvas2D15/지원CanvasKit12와 초기화 JS/WASM 응답을 확인했습니다. Mac WASM은 no-opt 로컬 대체 빌드입니다.

CI 보정은 편람 Gym 과제8건 제거에 따른 원장 기대 건수와 삭제된 case를 참조한 --print 대상 한 줄입니다. 제품 Rust·Studio source는 로컬 검증 head와 같습니다. 최종 PR head b1e93d8, 테스트 merge 41a30c3eeb6e50464b6806beeaa20dbaa23a77a8의 Full CI·CodeQL·Render Diff·Proptest·Adapter·Gym 검사가 모두 통과했습니다. Rust4 shard 합계11,288 PASS/0 FAIL/45 skip입니다.

원 PR별 검토 기록, 대응하는 review/overlay PNG·전쪽 TSV와 오늘할일을 포함합니다. 머지 후 사용자 지정 옵션2로 실제 CI·merge·후속 처리 기록을 보완합니다. 대표 #7445 전체 해결을 주장하지 않습니다.

Refs #8099, #8105, #7687, #8156, #7874, #8169, #8167, #8172, #4599, #7445, #7765, #7881

Co-authored-by: Jaeuk Ryu <35355437+planet6897@users.noreply.github.com>
@jangster77

Copy link
Copy Markdown
Collaborator

기여해 주셔서 감사합니다. 이 PR의 기능을 검토·체리픽 통합하여 PR #8228로 devel에 반영했습니다.

  • 확인한 원 contributor head: 6d20cb5353985492fcdd3340fc8c2ee699d9ed57. 원 source branch의 후속 변경 없이 같은 head임을 다시 확인했습니다.
  • 통합 merge: 3e02fe2749866a8453af3eb3901b9c1a674cccaf; 개별 PR 검토 기록은 문서 PR #8231에 확정했습니다.
  • 최종 head b1e93d8de2d4842f725415aee19bd5b98ecfb8b3의 Full CI·CodeQL·Render Diff·Proptest·Adapter·Gym 계약은 모두 성공했습니다.
  • 로컬 runtime source 673c1d5f7cdcb5573b793ba2d2abaaedd2602134에서 전체 nextest11,481 PASS/0 FAIL/45 skip, 별도 CI A/B/C/D 합계11,288 PASS/0 FAIL/45 skip입니다. 로컬과 CI 실행 수를 구분합니다.
  • 공통 전쪽 검증은 Native/fresh WASM 각각35조건·2,041쪽, 최저91.87422%/91.82753%, 90% 미만·누락·동일 조건 base 대비0.1%p 이상 하락0쪽입니다. 해당 원 PR에 대응하는 입력과 직접 판독은 아래 및 개별 기록으로 구분했습니다.

원 기여에서는 편집으로 만든 글상자의 HWP 저장 워드에 글상자 비트를 보존합니다.

원 기여와 통합 보정

생성·부착·제거·저장 재열기 검사와 원 기여자의 한컴 수용 근거를 구분했습니다. 비트 계약을 무관한 문서 그림으로 입증하지 않습니다.

원 기여 기능과 메인터너의 통합 보정 범위는 위 개별 검토 문서의 적용 commit·소비 경로·실제 회귀 결과에 구분했습니다. 다른 PR의 문서나 제외한 sample16·편람을 이 PR의 개선 증거로 대신하지 않았습니다.

이 원 PR에 대응하는 정식 회귀 3건의 실제 PASS는 개별 검토 기록에 기재했습니다.

직접 확인한 증적

공개 편집 API의 생성·부착·제거 및 HWP 저장·재열기 계약3건이 실제 전체 회귀에서 통과했습니다. 화면 위치 개선을 주장하지 않으므로 무관한 문서 그림을 첨부하지 않습니다.

Visual Sweep 비교·병합 판정 방법과 공통 producer·해시·잔여 원장을 연결합니다. 일치율은 내용 픽셀 중심 자동 비교 보조값이며 사람 판독의 정확도나 완전한 픽셀 동일성을 뜻하지 않습니다.

이 원 PR은 별도 직접 merge가 아니라 통합 PR에 반영했으므로 종료하겠습니다. contributor의 원격 브랜치는 유지합니다. 관련 이슈 전체의 완료 여부는 개별 증거 범위로 별도 판단하며 이 PR 종료만으로 일괄 종료하지 않습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api 공개 API/JS·WASM 바인딩/스캔·편집 API 계약과 소비자 호환성 bug Something isn't working roundtrip parse→serialize→reparse 및 IR/render diff 기반 회귀 검증 serialization 문서 저장/직렬화: HWPX/HWP 출력, XML/OLE 속성 보존, roundtrip 저장 정합성

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants