Skip to content

fix(table): 저장 첫 프레임 경로의 위 캡션 표 원점에 캡션을 두 번 더하지 않는다 (#7732) - #8131

Closed
planet6897 wants to merge 8 commits into
edwardkim:develfrom
planet6897:fix/source-frame-top-caption-origin
Closed

planet6897 wants to merge 8 commits into
edwardkim:develfrom
planet6897:fix/source-frame-top-caption-origin

Conversation

@planet6897

@planet6897 planet6897 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

요약

쪽 끝에서 나뉘는 쪽 나눔 표의 첫 조각이 저장 첫 프레임 경로(stored_complete_extent·첫 조각 빈 밴드)로 확정되고 앞선 배치 계획이 없을 때, 위 캡션이 붙은 표가 캡션 높이(약 25px)만큼 내려 그려지던 문제를 고친다. 첫 조각 아래 괘선이 본문 아래를 넘던 넘침도 함께 사라진다.

Refs #7732 (issue1937 20쪽의 원인 중 하나 — 이슈 전체를 닫지 않는다)

#8133 에 의존한다. 이 branch 는 upstream/devel d9fd85ed5 위에 #8133(#8125 가는 획 장치 한 칸 — Native Skia·WASM Canvas2D·CanvasKit)의 코드 커밋 6개를 그대로 얹었다(5개는 이 PR 커밋 아래, CanvasKit e89e55644 는 맨 위 — #8133 의 CI CanvasKit readiness 보정을 따라 얹었다). 새 표본 4쪽이 그 수정 없이는 0.48px 표 괘선이 옅게 찍혀 86% 대라, 회귀 추가 선행 조건(전쪽 Native/fresh WASM 90% 이상)을 충족하려면 #8133 이 필요하다. #8133 병합 뒤 rebase 하면 이 PR 의 diff 는 아래 두 커밋만 남는다.

  • 5d80f3047 fix(table): 원점에서 캡션 이중 계상 제거 + 표본·정본 PDF·회귀 검사
  • 692168436 docs(report): 수정 전후 review/overlay

원인

src/renderer/typeset/table/continuation/fragment/emit.rs 에서 이 경로가 원점을 새로 만들 때 위 캡션 높이 caption_extra 를 원점에 넣었다. 이후 소비 지점은 모두 원점을 위 캡션을 포함한 개체 상자의 위끝으로 보고 캡션을 한 번 더 더한다.

소비 지점 원점 사용
예산 budget.rs 프레임 = 하단 − 원점 − 캡션
확정 commit_fragment 캡션 + 조각 높이
그리기 table_partial.rs 표 = 원점 + 캡션 + 간격

그래서 캡션이 두 번 들어갔다. 이 이중 계상은 fd1a53fdc 에서 들어왔고, 그 커밋의 사례에는 위 캡션이 없었다.

변경

한 줄이다. 이 경로의 원점에서 캡션을 빼 current_height + host_before_overhead + vert_offset_overhead 로 만든다. 다른 원점 생산자와 같은 정의다.

  • 적용: 저장 첫 프레임 경로로 확정되고 앞선 배치 계획이 없는 첫 조각 중 위 캡션이 있는 표.
  • 비적용(값이 바뀌지 않음): 아래 캡션 표, 캡션 없는 표, 이어지는 조각. caption_extra 는 첫 조각의 위 캡션에서만 0이 아니다.

검증 (head 692168436)

이후 head e89e55644 는 #8133 의 CanvasKit 커밋(rhwp-studio/src/view/canvaskit-renderer.ts)만 더했다. Visual Sweep 의 Native·fresh WASM(Canvas2D) 출력과 회귀 검사에는 닿지 않는 경로라 아래 결과·이미지(692168436 고정)를 그대로 쓴다.

표본 교체

이전 표본 top_caption_rowbreak_p31.hwp 는 그 사이 devel 의 다른 변경으로 이 경로를 타지 않게 되어 수정 전에도 통과했다(이전 본문의 ⚠ 항목). 그래서 결함이 실제로 남아 있는 issue1937 20쪽에서 새 표본을 만들었다.

  • 입력 samples/issue1937/top_caption_rowbreak_p20.hwp — samples/issue1937_rowbreak_footnote_overpagination.hwp(50쪽)의 문단 126–145(18–21쪽)만 남겨 한/글 2024 로 다시 저장한 5쪽 문서. 저장 줄과 표 첫 프레임은 한/글이 다시 썼다.
  • 기준 pdf/issue1937/top_caption_rowbreak_p20-2024.pdf — 같은 저장본의 한/글 2024 Print 출력(5쪽).
  • 3쪽 끝 표(pi=18)는 위 캡션 «< 부담금 개별법령상 납부의무 완화 규정 종합 >» 을 달고 쪽 끝에서 나뉜다. 정본은 표 위 괘선 834.1px · 첫 조각 아래 괘선 1005.0px(96dpi)다.
  • 이전 p31 표본·PDF 는 이 PR 에서 뺐다.

전체 쪽 Visual Sweep

판정값 = raw 실루엣(TSV 4열), --compat 2024. 수정 전 = 같은 branch 에서 emit.rs 만 되돌린 빌드.

쪽 Native 수정 전 Native 수정 후 fresh WASM 수정 전 fresh WASM 수정 후
1 99.96 99.96 99.96 99.96
2 99.99 99.99 100.00 100.00
3 73.84 99.90 73.87 99.87
4 99.59 99.59 99.49 99.49
5 99.73 99.73 99.56 99.56
  • 쪽수: rhwp 5쪽 = 한/글 5쪽. 수정 후 90% 미만 쪽 없음(Native·WASM 모두, 최저 99.49).
  • render tree: 수정 후 캡션 줄 810.2–823.5px, 표 834.9–1006.2px(정본 캡션 글자 807.4–823.4 · 괘선 834.1/1005.0). 수정 전 표 위끝 859.6px.
  • 직접 판독(3쪽 아래): 수정 전에는 캡션과 표가 약 25px 내려가 overlay 에서 PDF 표와 어긋나고 셋째 행이 본문 아래로 넘친다. 수정 후 캡션·머리행·1~3행 괘선과 글자가 PDF 와 겹친다(Native·WASM 같음).

대표 이미지 (3쪽)

Native 수정 전 review / overlay

native base review
native base overlay

Native 수정 후 review / overlay

native head review
native head overlay

fresh WASM 수정 전 / 수정 후 review

wasm base review
wasm head review
wasm head overlay

회귀 테스트

tests/cases/issue_7732_source_frame_top_caption_origin.rs — stored_first_frame_top_caption_table_is_drawn_once_below_its_caption

  • 쪽수 5(한/글 2024 Print 정본).
  • 캡션 줄이 표 바로 위에 한 번 놓인다(캡션 아래 ≤ 표 위, 간격 12px 이내).
  • 첫 조각이 본문 영역 안에 든다.
  • 3쪽은 Native 99.90 · WASM 99.87(양쪽 98% 이상)이고 직접 판독을 마쳐, 정본 표 위 괘선 834.1px · 첫 조각 아래 괘선 1005.0px 을 ±2px 로 고정한다.
  • 수정 전 실패(emit.rs 만 되돌린 빌드): 표가 캡션 높이만큼 내려 첫 조각이 본문 아래를 넘는 assertion 에서 실패. 수정 후 통과.

게이트 (head 코드)

  • fmt diff 0, Clippy(native · wasm32 · workspace all-targets · native-skia all-targets), workspace build, manifest --check 통과.
  • nextest(--features native-skia) 11,531건 중 11,528 통과. 실패 3건 issue_7966_pdf_close_stroke::* 는 이 host 의 core.autocrlf=true 가 fixture pdf/issue7966/close-stroke-controls.pdf 를 CRLF 로 꺼내 바이트가 바뀐 탓이다(ImportResourceLimit). 저장소 blob 그대로의 바이트로 되돌리면 3건 모두 통과한다. 이 변경과 무관하다.

원문 문서(보조 증거)

발췌 전 원문 samples/issue1937_rowbreak_footnote_overpagination.hwp 20쪽: Native 70.93 → 94.03, fresh WASM 71.30 → 94.92. 원문에는 이 수정과 무관하게 수정 전후 값이 같은 90% 미만 쪽(21·33–43쪽, Native 는 49쪽 포함)이 남아 있어 검증 대상·fixture 로 쓰지 않고 보조 증거로만 적는다. 이 PR 은 #7732 전체를 닫지 않는다.

미검증

  • 10k 코퍼스·samples A/B 의 넓은 영향(12문서 넘침만 감소, 쪽수 변화 없음 / samples 변화 없음)은 이전 head(같은 emit.rs 한 줄)에서 잰 값이며 새 base 에서 다시 재지 않았다.
  • 한/글이 저장한 합성 입력(위/아래/없음 캡션, 오프셋)은 이 경로를 타지 않아(host 배치를 받음) 다른 경로의 무변화만 확인했다.

🤖 Generated with Claude Code

@edwardkim edwardkim added bug Something isn't working layout 문서 레이아웃/페이지네이션: 표·그림 배치, float/anchor, 줄·행 높이, 겹침·클리핑 rendering SVG/Canvas/PDF 등 렌더 출력과 시각 표시: 그리기, 표시 누락, bbox, paint 정합성 table table rendering and edit labels Oct 21, 2026 — with ChatGPT Codex Connector
@edwardkim edwardkim added this to the v1.0.0 milestone Oct 21, 2026 — with ChatGPT Codex Connector
@planet6897
planet6897 force-pushed the fix/source-frame-top-caption-origin branch from 5906b14 to a92ed55 Compare October 23, 2026 15:53
한컴 Print PDF 를 raster 로 읽으면 0.1 mm 안팎(0.3~0.5 px) 표 괘선도 장치 한 칸을
채운다. Native Skia 는 선언 굵기 그대로 anti-alias 해 괘선 덮임이 20~45% 에 그쳐
실루엣에서 괘선이 빠졌다(issue1937 p49 간트 표 89.28).

raster 대상에서 도형 획·직선(이중선 각 획 포함)·쪽 테두리의 굵기를 현재 canvas
변환의 장치 한 칸 이상으로 그린다. 합성 굵게의 윤곽 획이 쓰던 같은 규칙을
line_replay 의 공통 helper 로 옮겨 함께 쓴다. 조판 좌표·선언 굵기·점선 간격과
벡터(PDF·SVG)·WASM 출력은 바뀌지 않는다.

- issue1937(edwardkim#8115 적층) p49 89.28 → 99.997, 90% 미만 25 → 23쪽
- samples 517문서(앞 40쪽) 쪽별 raw: 상승 396 · 하락 76(최대 -1.38) · 신규 90% 미만 0
- samples/basic/calendar_year.hwp 88.25 → 98.87(fresh WASM 93.80)
- 회귀: tests/cases/skia_subpixel_stroke_hairline.rs (수정 전 실패, native-skia CI 등록)
…8125)

ci.yml 의 Native Skia job 에 추가한 파일 게이트 test 를 classifier 의
NATIVE_SKIA_RUST_FILES 와 그 단위 검사 목록에도 올린다. 빠지면 그 파일만 고치는
PR 에서 Native Skia job 이 skip 되고, test_ci_impact_workflow 계약이 Lint 를 실패시킨다.
fork PR 은 .github/workflows 와 scripts/ci-impact-classifier.cjs 를 바꾸면
신뢰 CI 정책이 "Untrusted head changed the enforcement surface" 로 막는다.
새 파일을 CI 목록에 등록하는 대신, 이미 Native Skia job 과 classifier 에 등록된
tests/cases/native_fractional_glyph_origin.rs 의 하위 모듈로 같은 검사를 옮기고
ci.yml·classifier 변경은 base 로 되돌린다. 검사 내용은 그대로다.
Native Skia 의 floor_stroke_to_device 와 같은 PDF raster 의 얇은 선 규칙을 WASM Canvas2D 에
적용한다. 현재 canvas 변환의 역으로 장치 한 칸의 local 길이를 구해 도형 획과 선(단선·다중선)의
굵기 하한으로 쓴다. 조판 좌표·선언 굵기와 점선 간격(하한 전 굵기로 정함)은 바꾸지 않는다.

- calendar_year 1쪽 fresh WASM raw 실루엣 94.37 → 98.88 (Native 98.87 과 같아짐).
- sungeo 94쪽 fresh WASM: 상승 77 · 하락 0 · 불변 17, 90% 미만 쪽 수 그대로(p21·22, 별개 차이).
- issue1937 18~21쪽 발췌(한/글 2024 재저장) 4쪽 0.48px 칸 괘선: 86.67 → 99.49.
- 회귀: rhwp-studio/e2e/issue-8125-hairline-canvas2d.test.mjs (npm e2e:issue-8125-canvas2d) —
  수정 전 calendar_year 가는 가로 괘선 182곳 미달, 수정 후 0곳.
쪽 끝에서 나뉘는 쪽 나눔 표의 첫 조각이 저장 첫 프레임(stored_complete_extent·첫 조각 빈 밴드)
경로로 확정되고 앞선 배치 계획이 없으면 emit 이 원점을 새로 만든다. 그 원점에 위 캡션 높이
(caption_extra)를 넣었다. 예산(프레임 = 하단 − 원점 − 캡션), 확정(commit_fragment 의 캡션 +
조각 높이)과 그리기(table_partial 표 = 원점 + 캡션 + 간격)는 모두 원점을 위 캡션을 포함한 개체
상자의 위끝으로 쓰므로 캡션이 두 번 들어가 표가 캡션 높이만큼 내려 그려졌다.

- 표본 top_caption_rowbreak_p20.hwp(issue1937 보고서 50쪽의 문단 126–145 를 한/글 2024 로 다시
  저장, 5쪽): 3쪽 끝 표 pi=18 위 괘선이 한/글 2024 Print 정본 834.1px 에 놓인다(수정 전 859.6).
  Visual Sweep 판정값(raw 실루엣) 3쪽 Native 73.84 → 99.90, fresh WASM 73.87 → 99.87, 나머지 쪽 불변,
  5/5쪽 99 이상(edwardkim#8125 가는 괘선 장치 한 칸 위에서).
- issue1937 원본 20쪽: Native 70.93 → 94.03, fresh WASM 71.30 → 94.92.
- 회귀: issue_7732_source_frame_top_caption_origin (수정 전 실패: 표가 캡션 높이만큼 내려 첫 조각이 본문 아래를 넘는다).
…k_p20 3쪽 수정 전후 Native/fresh WASM review·overlay
Canvas2D 에 장치 한 칸 획 하한을 넣자 CI CanvasKit readiness 의 Canvas2D↔CanvasKit
시각 일치(table-core 0.0495 > 0.047, table-border-style 0.0075 > 0.006)가 깨졌다.
CanvasKit 도 0.48px 표 괘선을 선언 굵기대로 anti-alias 해 옅게 그리던 같은 결함이다.

- renderPage 의 배율(zoom × dpr)에서 장치 한 칸의 page 길이(1/scale)를 잡아, Canvas2D 가
  하한을 둔 같은 자리(도형 외곽선·그림자 외곽선·직선/이중선 각 획)의 굵기 하한으로 쓴다.
- 획 굵기가 배율을 따르므로 정적 picture 캐시 키에 배율을 넣는다.
- 글자 장식·쪽 테두리·글리프 외곽 획은 Canvas2D 와 같이 바꾸지 않는다.
@planet6897

Copy link
Copy Markdown
Contributor Author

devel 에 이미 반영되어 닫습니다

#8191 이 devel 에 들어간 뒤 이 PR 이 충돌 상태가 되어 다시 확인했습니다. 이 PR 의 코드 없이 최신 upstream/devel 9418ed0c7 에 이 PR 의 회귀 검사와 표본(samples/issue1937/top_caption_rowbreak_p20.hwp)만 얹어 실행하면 통과합니다.

회귀 검사 devel 9418ed0c7
issue_7732_source_frame_top_caption_origin::stored_first_frame_top_caption_table_is_drawn_once_below_its_caption 통과 (표 위 괘선 정본 834.1px ±2)

devel 의 저장 첫 프레임 경로가 위 캡션 표 원점에 캡션을 두 번 더하지 않게 되어, 이 PR 의 emit.rs 한 줄 수정이 더 필요 없습니다. 이 PR 은 닫습니다.

@planet6897 planet6897 closed this Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working layout 문서 레이아웃/페이지네이션: 표·그림 배치, float/anchor, 줄·행 높이, 겹침·클리핑 rendering SVG/Canvas/PDF 등 렌더 출력과 시각 표시: 그리기, 표시 누락, bbox, paint 정합성 table table rendering and edit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants