Skip to content

fix(layout): read a negative page margin kept unsigned as negative - #464

Merged
airmang merged 6 commits into
mainfrom
fix/page-estimate-signed-margins
Oct 16, 2026
Merged

airmang merged 6 commits into
mainfrom
fix/page-estimate-signed-margins

Conversation

@airmang

@airmang airmang commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

바뀐 점

머리말·꼬리말 여백이 음수인 문서는 그 값을 부호 없는 32비트로 남긴다(-1400이면 4294965896). .hwp를 HWPX로 바꾼 문서에 이런 여백이 있다. 쪽 수 추정과 배치 검사가 이 값을 큰 양수로 읽어 본문 높이가 음수가 되었고, 쪽 수 추정은 빈 쪽을 끝없이 넘기며 끝나지 않았다(2쪽짜리 문서에서 멈춤). 한/글은 이 값을 음수로 읽어 본문을 그만큼 늘린다.

마이너스 기호로 쓴 여백(header="-1400")은 다르다. 한/글은 이 값을 읽지 않고 그 변의 새 쪽 여백(위 5668, 아래 4252, 왼쪽·오른쪽 8504, 머리말·꼬리말 4252, 제본 0)으로 쪽을 놓은 뒤 그 값으로 저장한다.

  • src/hwpx/oxml/section_format.py: _page_margin(value, side) — 부호 없는 32비트 꼴은 부호 있게, 마이너스 기호 꼴은 그 변의 새 쪽 여백으로 읽는다.
  • src/hwpx/layout/pages.py _page: 본문 높이·위치·글 너비를 _page_margin으로 계산한다. 여백 때문에 본문 높이나 글 너비가 0 이하이면 page margins leaving no room for the body로 지원 밖을 돌려준다(끝없이 돌지 않는다).
  • src/hwpx/layout/lint.py: 같은 본문 높이 계산에 _page_margin을 쓴다.
  • CHANGELOG.md: [Unreleased] 고침에 한 항목.

테스트

  • 한/글 저장 고정본 6개(tests/fixtures/hancom_saved/pages_margin_negative_*): 머리말 -1400, 꼬리말 -3600, 둘 다(-4000·-3600) 여백에 한 줄 문단을 늘린 본문을 꼭 채우는 수만큼 넣은 문서는 1쪽, 한 줄 더 넣은 문서는 2쪽(한/글이 저장한 줄 위치로 확인). 줄 캐시가 있을 때와 없을 때 모두 같은 쪽 수.
  • 한/글 저장 고정본 1개(pages_margin_minus_sign_header): 머리말을 "-1400"으로 쓴 문서를 한/글이 새 쪽 여백 4252로 놓고 저장한 것. 머리말 "-1400"·"-4000", 위 "-1000"으로 다시 써도 한/글과 같은 2쪽.
  • 여백이 본문을 없애는 문서는 지원 밖으로 보고하는 시험.
  • 고치기 전 main에서는 부호 없는 꼴 고정본의 쪽 수 추정이 끝나지 않고, 마이너스 기호 시험은 1쪽으로 틀린다. 극단값(2^31, 2^32-1, 모든 변 음수, 용지보다 큰 여백)에서 추정이 바로 끝나는 것을 확인했다. ruff·mypy·pyright 통과, 전체 시험은 main과 같은 결과.

🤖 Generated with Claude Code

airmang and others added 2 commits October 15, 2026 00:58
A negative header or footer margin is kept as an unsigned 32-bit number
(-1400 as 4294965896), as a .hwp converted to HWPX has it. The page
estimate and the layout lint read it as a large positive one, so the
body height went negative and the estimate never ended. Hancom reads it
as negative and makes the body that much taller; both now do the same.
Margins that leave no body height or text width make the estimate
report the page as unsupported instead of looping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e margin

A page margin written with a minus sign (header="-1400", not the unsigned
form) is not one Hancom reads: it lays the page with the new-page margin
for that side (top 5668, bottom 4252, left and right 8504, header and
footer 4252, gutter 0) and saves that. The page estimate and the layout
lint read it as negative; they now take the new-page margin too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@airmang airmang left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

44891e3 검토 완료. 부호 없는 32비트 여백의 부호 해석, 마이너스 기호 여백의 변별 기본값, 본문 영역이 없어질 때의 종료 처리를 검토했고, 이 변경에서 재현된 코드 결함은 찾지 못했습니다. 별도 Python 3.12 체크아웃의 관련 회귀 테스트 1423개가 모두 통과했고 해당 head의 GitHub 검사 13개도 모두 성공했습니다. 다만 #462/#463 병합 후 최신 main dd67a530bf656a1deb38c1192937a755a49346d0과 병합하면 CHANGELOG.md에서 내용 충돌이 발생합니다(GitHub DIRTY/CONFLICTING 및 git merge-tree로 확인). 예약 작업의 병합 조건에 따라 이번에는 보류합니다. main을 merge해 양쪽 변경 기록을 유지하고 충돌을 해결한 뒤 최신 head의 검사를 다시 통과시키면 재검토할 수 있습니다.

@airmang airmang left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

부호 없는 32비트 쪽 여백의 음수 변환, 마이너스 기호의 기본 여백 처리, 본문 공간이 없는 경우의 종료 처리를 검토했습니다. 최신 main과의 충돌을 양쪽 기록을 보존해 해결했고, 검토한 소스의 Python 3.10–3.14 전체 CI와 CodeQL·의존성 검사가 모두 통과했습니다. 같은 커밋의 중복 PR 테스트 실행 5건은 취소했고 push 매트릭스 성공을 확인했습니다. 통합 테스트 1,692개와 재배치 전후 의미 비교도 통과했습니다. 검토한 head를 지정하여 squash 병합합니다.

@airmang
airmang merged commit 0112bc0 into main Oct 16, 2026
8 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant