Skip to content

fix(조판): RowBreak 표 분할·이어받기를 저장 쪽 경계 기록대로 — 1342000 쪽 수 415 일치·21761835·1480000·1613000 (부분 개선) - #7965

Open
planet6897 wants to merge 59 commits into
edwardkim:develfrom
planet6897:fix/devel-table-scan-regression

Conversation

@planet6897

@planet6897 planet6897 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

PR base: devel. devel efc52afb7 위로 다시 올렸다(이전 head 21ab9623d 는 devel 과 충돌). code head 9f2b24150, 증적 head 690290fa9. 최신 devel 2e3b4f880 과도 충돌 없음(git merge-tree). 리베이스로 커밋 해시가 모두 바뀌었고 이 본문의 해시는 새 해시다. 대표 PNG 와 전쪽 TSV 는 모두 code head 9f2b24150 에서 새로 찍었다(Native --features native-skia, fresh WASM rhwp_bg.wasm SHA-256 c4ed9986a26ba804b2a1bb51c48397e794a411c49e10407bf32e5088a5ea16e6). devel 대조 열은 base efc52afb7(공유 바이너리 ~/rhwp_shared/bin/efc52afb7_skia).

리베이스로 바뀐 것. devel 이 그사이 #7642(재조판 프레임 inset)·26877eedf(걸침 칸 예외 제거)·저장 줄 신뢰 정책을 들여와 세 가지가 새로 필요했다. 아래 표 맨 끝 세 커밋이다: ① 50dcb0078 쪽 끝 띠의 방을 실제 예약 높이에서 잼(21761835 2쪽·1613000 154쪽) ② f8fa0f02a 병합 칸 HWP5 저장 표의 원본 프레임 예산만 100HU inset 제외 + devel 걸침 예약의 상자·예약 불일치 수정(1342000 149–151쪽, devel 시험 issue_7692·issue_6981 유지) ③ 065125a94 한/글 2014 저장 줄의 낱말 꼬리(#7702, 원래 #8092 로 냈던 커밋을 여기에 합침) — 이것 없이는 1342000 이 416쪽이고 이 PR 의 rows_inside_a_crossing_rowspan_still_split_after_one_line 이 실패한다. 리베이스 중 f935ccc7f(clippy 정리)는 충돌 해소에 흡수돼 사라졌다.

변경 요약

devel 의 RowBreak 표 분할·이어받기 경로에서 한/글 Print PDF 와 어긋나던 쪽 경계·행 높이·셀 정렬을 고친다.
모두 저장 조판 정보(셀 LineSeg vpos 재시작, 선언 행·칸 높이)를 한/글이 남긴 쪽 경계 기록으로 읽는 방향이며,
문서 ID·좌표 예외는 없다. 리베이스 뒤 55개 커밋(코드 32 + style 2 + 증적 21).

커밋 규칙 근거 문서(한/글 PDF)
03ed94157 첫 개체 프레임 뒤 행의 원점0 재시작은 그 행이 쪽 끝에 걸릴 때만 자른다 issue1853 16쪽
e0441c319 첫 분할 행의 이어받기 물리 잔여는 선언 행 상자를 넘지 않는다(측정 초과분은 내용 높이) 80168 61쪽
80168 5쪽
a7bc0ba8f 저장 vpos 가 되감긴 atomic TAC 그림은 하단 여백으로 스필하지 않는다 —
c04da55b3 0행 rowspan 묶음은 0행만 잔여에 들 때 0행 뒤에서 자른다 1480000 표 9·17
33ebbc01e 저장 근거가 증언한 행의 빈 띠를 다음 쪽으로 넘기고 끝 조각 아래 여백을 예약 1480000 46·47쪽
cd5bebf6d·eb9d271c2 걸침 칸 없는 짧은 쪽 끝 행은 통째로 넘기고, 블록 끝 행의 빈 띠는 선언 초과가 말미 압축 허용치(13px) 이내일 때 쪽 경계에서 닫는다 1480000 48·49·53·54쪽, 21761835 4쪽
14a1bb320 쪽 마지막 행이 셀 저장 줄의 새 원점 재시작을 가지면 그 줄에서 자른다 1480000 43·44쪽, 1613000 126·127쪽
6f1ac9323 분할 표 뒤 빈 줄은 다음 문단의 저장 위치가 자리를 남기면 그린다 1480000 44쪽
5b662bb18 걸침 칸의 미지 행은 가장 먼저 끝나는 제약이 정하고, 쪽을 넘어온 칸의 남은 높이를 끝 행에 준다 21761835 2쪽
a92d0d220 문단 경계 저장 쪽 재시작으로 끝나는 분할 행도 원본 조각으로 보고 칸 정렬을 따른다(칸 하나뿐인 표 제외 — 이미 다른 경로가 정렬) 1342000 31쪽, 17253153 3쪽
5994ce798 한/글 저장 쪽 경계(vpos 0 재시작)에서 끊긴 걸침 행도 기존 #7531 쪽 끝 띠 경로에 들인다. 띠는 max(나뉜 행의 남는 몫, 걸침 칸의 남는 몫) 까지, 그 끝 행 상자는 end_row_owns_stored_frame, 다음 조각은 그 상자를 이어받는다 21761835 2·3쪽 / 반례 70833 2쪽
b30e9e020 위 쪽 끝 띠를 문단 유지 계약 밖의 모든 내용 컷(예산 컷 포함)으로 넓힌다(같은 몫 상한) 1342000 416→415쪽 (200쪽 행 75 띠 → 202쪽 행 92 가 선언 97.1px 로 돌아옴)
200beb58f ① 표 선언 높이가 행 경계 선언 합과 같고 그 경계를 닫는 행만 자랐으면 행을 줄이지 않는다 ② 첫 조각 원점은 문단 윗변 + 세로 오프셋(생성 경로마다 다른 앵커 의미를 호출자의 문단 시작으로 판별 — 위 간격 이중 차감 제거) ③ 글자 있는 호스트의 끝 조각 뒤 문단은 그 쪽 저장 줄 윗변을 따른다(공통 helper, 간격 ≤ 0 만) — typeset 흐름 끝·배제 띠도 같은 값 ④ 저장 앵커 분할 판정은 위 간격을 더한 흐름으로도 대조(다음 문단 vpos 되감김이면 제외) 1613000 185–190쪽, issue1880 1·2·4쪽(한컴 2024) / 반례 hwpspec 표 40
dd2e52e71 새 쪽 첫머리에 통째로 든 표(분할 루프의 0행·이어받기 아님 분기)도 끝 조각이다 — 흐름 끝을 위 ③ 의 같은 helper 로 정해 뒤 문단을 저장 줄에 둔다(종전: 행 높이 + 호스트 간격만 전진, 세로 오프셋·바깥 여백 누락) 1613000 191–193쪽 (상자 아래 631.9px = pi=10 줄 vpos 47394)
b4452b801 ① 셀 저장 줄의 새 원점 재시작에서 자른 쪽 끝 행(14a1bb320)은 남은 쪽 공간이 아니라 max(행 선언 높이, 자른 줄까지의 내용 높이) 상자에서 닫는다 — 공통 helper stored_restart_end_row_box 를 scan 이 예약하고 paint 는 같은 컷·같은 상자면 끝 줄간격을 접지 않는다 ② 끝 조각의 아래 캡션은 통째 표처럼 표 아래 + 캡션 간격에 둔다(호스트 줄간격은 캡션 뒤 흐름 끝에만, 흐름·쪽 나눔 불변) 1613000 126–128쪽, 1480000 43쪽, myeonjeok 1쪽(한/글 2020 MCP 변환본)
65e20ecba 이어지는 조각에서 걸침 칸 안의 쪽 끝 행은 선언 높이가 넘쳐도 내용이 비끝 조각 닫는 선(본문 아래 − 바깥 아래 여백 − 100HU, 1×1 조각의 SINGLE_CELL_PAGE_FRAGMENT_BOTTOM_INSET_HU 와 같은 값) 안에 들면 이 쪽에 두고 상자를 그 선에서 닫는다 — 다음 조각은 다음 행부터. 예산이 바깥 아래 여백을 예약하지 않은 표는 그 여백도 뺀다. 이 행에서 닫히는 칸이 없는 행·Stage 76 빈 띠 경로·첫 조각은 제외 1613000 195–202쪽, 1342000 335–345쪽 / 반례 80168 행 23, 76076 행 14
35f46f163 통째로 받은 끝 행의 쪽 끝 띠(#7531 경로)를 같은 닫는 선까지만 그린다. 닫는 선 아래 몫은 걸침 칸이 다음 쪽으로 넘기지 않으므로 이월 원장(page_end_band·끝 행 상자 기록·stored_reset_band_row_box·accepted_straddle_fragment_units)은 줄이기 전 띠를 소비한다. 내용 컷으로 끝난 행은 그대로 1613000 195쪽 상자 713.03px(PDF 712.91), 샘플 95쪽 +0.3~+1.8
7be2810a5 걸침 칸 안 쪽 끝 행 상자 = max(컷까지 내용, 행 선언, 걸침 칸마다 «선언 − 이 칸의 앞 행 상자»), 닫는 선 상한. 통째 끝 행에도 적용하고 그 상자는 원본 프레임(paint 끝 줄간격 접기 생략). 이어받은 시작 행은 측정 높이를 앞 행 상자로, 나뉜 행 보존 몫은 선언 높이로. 칸에 개체가 있는 행은 종전 계산. 내용 컷 행에서 줄인 몫은 걸침 칸의 다음 조각 앞 행 상자로만 넘긴다 1613000 139–183쪽(끝 행 47쪽 중 43쪽 PDF ±0.2px), fragment_ghost 14·15쪽 / 반례 1342000 336·337쪽, 1341000 29쪽
23db8512f 여러 쪽에 걸친 행의 이어받는 조각도 셀 저장 줄의 시작 컷 뒤 첫 새 원점 재시작(문단 안 vpos 0, 또는 앞 문단이 같은 셀 좌표로 이어진 문단 첫 줄 vpos 0)에서 닫는다 — 그 컷이 용량 컷 안에 있을 때만. 종전 helper 는 행의 첫 재시작만 찾아 이어받는 조각은 남은 쪽을 채웠다 1613000 123–125쪽 (표 pi=1133 컷 [41,37]→[40,37], [51,72]→[51,70]; 표 아래 선 PDF ±0.1px)
8c847d933 끝 조각 뒤 문단의 저장 줄 윗변이 표·캡션 상자 아래와 같으면 그 문단 위 간격은 상자 안에 있다 — 공통 helper text_host_terminal_successor_gap 를 빈 호스트로 넓힌다(뒤 문단 줄 상자가 줄간격·아래 간격까지 본문 안에 들 때만). NextLine 배치 계획이면 stored_successor_line_origin 으로 인증해 paint 도 호스트 아래 간격을 더하지 않는다 1613000 125쪽, issue1853 48·49쪽, task2070 72–110쪽(쪽 수 316→315 = 한/글 2020 변환본) / 반례 1613000 190쪽 pi=8(빈 줄 감추기)
2dfc0f184 1×1 상자 안 중첩 표가 쪽을 넘으면 상자도 가른다: ① #4533 절대배치 캡이 호스트 위 저장 줄 간격을 이 표의 예약 공간으로 오인하지 않게 앞 문단 흐름 중첩 표 끝을 갭 시작점에 넣는다(공통 helper nested_host_gap_start, 측정·배치 공유) ② 중첩 표 개체 높이가 앞 k개 행 상자 합과 정수로 같고 병합 칸이 그 경계를 가로지르지 않으면 한/글이 저장한 첫 조각 경계로 보고 k행 유닛을 셀 내부 쪽 나눔으로 보존, 중첩 행 경계는 고아 줄 되감기 대상에서 뺀다 ③ 1×1 첫 조각 계획이 흐름 원점에 바깥 위 여백을 이미 담으면 다시 더하지 않는다 ④ 끝 조각 뒤 문단의 저장 줄이 상자 아래 이하에 있으면 그 줄이 문단을 닫는다(stored_successor_line_origin 을 '상자 아래 이상'으로 일반화 — 기존 생산자는 모두 origin = 상자 아래) ⑤ 칸 안 어울림·왼쪽·오프셋 0 중첩 표는 저장 앵커를 쓴다(#3308 좁은 표 가운데 규칙에서 제외) 1613000 58·59쪽 (상자 측정 920.5→1099.4px, 11×4 표 6006HU = 행 0–2 상자 합 → 컷 [32]; 22×2 표 괘선 PDF 와 같음) / 반례 1341000 표 113(중첩 8×3 병합 행·고아 되감기), 1977964 1쪽 표 왼끝 85.50→84.83(한/글 2020 변환본 84.67)
55ddf0690 빈 꼬리말 밴드가 각주를 모두 받아 각주 차감이 0 인 쪽에서, 각주 보수 여백(3000HU)이 각주 자신의 높이를 넘어 본문을 깎지 않는다 — 가용 높이 하한 = 본문 − 각주 높이(paint 가 각주 영역을 여는 자리). 그 밖의 각주 예약은 그대로 1613000 85쪽 (84쪽 빈 문단 pi=817 저장 줄 936px < 각주 구분선 950.4px — 종전 본문 끝 931.4px)
06dc305d5 표 개체 높이가 행 상자 합보다 작게 저장된 원본(첫 조각 프레임만 저장 — native_stored_table_has_fragment_frames)도 셀 사다리 되감김 표처럼 '한/글이 쪽에서 가른 표'로 보고 #1672 가로 용지 경계 행 허용치를 끈다 1613000 198쪽 (197쪽이 빈 구분 행 96 을 본문 아래로 받던 것), 156505020(#5828 픽스처 원본) 41→43쪽 = 한/글 2020 변환본
de2315e55 문단 유지 계약이 저장 글줄 없는 문단(한/글이 줄 정보를 남기지 않은 셀)을 통째로 제외하던 것을, 문단 끝 컷에는 저장 글줄을 요구하지 않게 좁힌다(문단 안 컷은 그대로 저장 글줄 필요). 걸침 칸이 가로지르는 행의 첫 문단 컷이 25px 최소 상단 문턱에 버려지지 않는다 80168 61쪽 (표 pi=516 행 12 첫 문단에서 60쪽을 닫음)
50dcb0078 (리베이스 후속) 쪽 끝 띠의 방을 스캔이 실제 예약한 높이(split_end_reserved, 패딩 포함 컷 상자)에서 잰다 21761835 2쪽, 1613000 154쪽
f8fa0f02a (리베이스 후속) 병합 칸이 있는 HWP5 저장 표의 원본 프레임 내용 예산은 비끝 조각 100HU inset 없이 잰다(재조판 프레임·paint 상한·통째 끝 행 닫는 선은 devel 대로 inset). 그리는 띠의 inset 이중 차감 제거. devel 걸침 예약(stored_span_fragment_minimum)이 상자를 minimum−Σ저장행 만큼 키우면서 예약은 minimum 까지만 올리던 불일치를 grow = minimum − consumed 로 통일 1342000 149–151쪽(149쪽 아래 괘선 715.43 ↔ PDF 716.0), devel issue_7692·issue_6981
065125a94 (#7702) 한/글 2020 이전 제품이 저장한 양쪽 정렬+condense 문단의 마지막 줄이 앞 줄 낱말의 나머지뿐이면, 같은 프레임으로 새로 끊어 그 줄만 없어지고 앞 줄 시작이 그대로일 때 저장 줄을 버린다. 측정기 #6135 저장 extent 증인은 다시 끊은 문단의 옛 사다리를 쓰지 않는다 1342000 416→415쪽, 151·154쪽 / 반례 114·25쪽, 21_언어 1쪽
478da8250 쪽 끝 행을 내용 컷(그 행 칸의 저장 재시작)으로 가를 때, 그 행에서 끝나는 걸침 칸의 끝 유닛은 내용 컷이 아니라 그 조각에 그린 상자(끝 행 물리 높이)까지 맞춘다. 다음 조각은 carry 의 끝 유닛에서 잇는다 1342000 199·200·202·203쪽 — 199쪽 r62 c8 셋째 줄이 PDF 처럼 199쪽에 남아 200쪽 첫 행 +2.9px 와 202쪽 행 92 +2.9px(걸침 원장 이월)가 사라짐
f296dbc21 (#7702) 휴먼명조 ASCII 전진폭을 글꼴 파일(HMKMM.TTF) hmtx × 2 로 바꾸고(#2430 COM 래더 표는 , . ( ) 가 10pt 에서 한 장치 단위 좁았다), 공백 condense 로만 들어가는 문단 끝 줄은 양쪽 정렬 끝 글자를 자간 없는 폭으로 잰다(#5678 — #2470 의 문단 끝 예외는 자연폭으로 들어가는 줄에만) 1342000 189쪽 …실천한 / 다.(한/글 2024 폭 사다리 경계 26712 HU 와 같아짐), issue5169 4쪽, 36382669 5–7쪽(한/글 2024)
1cf3b879b (#8101) noAdjust(표 속성 bit 3) 표의 비끝 조각은 #7095 inset(100HU) 없이 본문 아래 − 바깥 아래 여백에서 닫는다. 예산·그리기 띠·원장·걸침 칸 닫는 선이 표마다 정한 같은 inset(rowbreak_fragment_bottom_inset_hu)을 쓴다. noAdjust 아닌 표는 그대로 1342000 126–129쪽 — 걸침 칸 «생활안전»(1–60행) 몫을 조각마다 100HU 덜 소비해 끝 행 60 이 +490HU 커지던 것이 사라져 126쪽 끝 줄이 PDF 처럼 남음. 한/글 2020 쪽 끝 괘선: noAdjust 121·170·99·49쪽 = 본문 아래 − 바깥 아래 여백(±0.15px), 아닌 표 157·213·108쪽 = 그 선 − 100HU
e64b513ed (#8105) ① 이어지는 조각의 바깥 위 여백 재개방에서 vertical_offset == 0 조건 제거(오프셋은 첫 조각에서 소진) ② 다음 문단이 자기 앞 간격 원점으로 되감기는 저장 경계에서 앞 줄 뒤 줄간격을 조각에서 뺌 ③ #6143 «문단 오프셋 소진» 판정의 25px 최소 조각을 나눌 수 없는 0행 높이로 넓히고, 소진된 첫 조각은 그 쪽에서 바깥 위 여백을 연다(그리기 OR 묶음 — 다른 규칙이 이미 연 형상에 이중으로 열지 않음) 1342000 26–34·51·53–57쪽(구역 1 표 이어지는 윗변 = 본문 위 + 141HU, 55쪽 행 21 p0·p1), hwpx_sample2(한/글 2024) 6·7쪽 — 6쪽 첫 조각 = 저장 첫 프레임 1038.01px, 75544 hwpx 31·32쪽, 1480000 41쪽
51a628363 (#8105) 내용이 이 쪽에서 끝난 분할 행의 남은 선언 높이(선언 − 그린 높이)는 1282HU(17.09px) 를 넘으면 다음 쪽 첫머리 빈 띠, 이하면 쪽 경계에서 흡수한다(한/글 2024 합성 사다리 — 17.0 흡수·17.2 이월, 칸 여백 283/500·표 기본 여백 141/400·글자 10/16pt·저장 줄·병합 칸 유무와 무관). ① 저장 줄 행(재조판 없음)도 이 규칙을 따른다 — 종전엔 걸침 칸이 덮는 저장 줄 행의 띠를 버렸다 ② 저장 줄 행의 분할 예산이 본문 아래까지 가 끝 행 상자가 paint 닫는 선보다 383HU 컸던 것을 원본 프레임 예산에서 자른다(원장도 같은 값) — paint 는 선언 안의 그 상자를 끝 줄간격으로 접지 않는다 ③ 그 행에서 끝나는 병합 칸의 남은 선언도 띠가 된다(재조판 칸만 계산하던 것을 내용이 끝난 저장 줄 행으로 넓힘 — 블록 컷 조각은 제외) 1342000 59·61·62·307쪽(59쪽 띠 25.9px = 선언 9366HU − 58쪽 98.9, 61쪽 51.6px = 행 8–17 병합 칸 선언 103310HU 의 남은 몫), 합성 samples/issue8105/declared_row_band.hwpx 12쪽(한/글 2024)
9f2b24150 (#8105) 문단 머리(번호)를 그리는 칸 문단도 한/글 2020 이전 저장 줄의 낱말 꼬리를 다시 나눈다 — #7702 의 «새 줄 나눔이 저장 줄 꼬리만 앞 줄로 흡수하면 다시 나눈다» 의 대상을 condense 문단에서 «condense 또는 문단 머리» 로 넓힘(stored_last_row_is_rejoinable_word_tail). 한/글 2024 합성(probes/make_numbered_stale_tail.py): «-»·«1.» 번호를 그린 문단은 폭이 맞는 저장 줄도 한 줄로 다시 나누고, 번호 없는 문단은 폭이 맞으면 저장 줄 그대로(줄 flags·저장 제품 버전 무관). 실제로 붙는지는 종전대로 새 줄 나눔이 정한다 1342000 250·251쪽 (행 49 69.1→51.9px = 선언), 90% 미만 123→97

관련 이슈

Refs #7445 · #5941 · #6764 · #2146 · #2236 · #7702 · #8101 · #8105 — 부분 개선. 아래 「남은 차이」의 쪽을 해결하지 않았으므로 어느 이슈도 닫지 않는다.

후속: #8079 (굵은 맑은 고딕 전진폭 — 80168 133쪽의 원인, 표 분할 밖). #7702 분석: #7702 (comment)
(#7445 의 1342000 쪽 수는 415 = PDF.)

대표 쪽 (Native·fresh WASM × review·overlay, 모두 90% 이상)

문서·쪽 기준 PDF devel(efc52afb7) 브랜치 Native 브랜치 WASM
1613000 58쪽 pdf/1613000-202200037-air-traffic-controller-cbta-2020.pdf 82.5 98.7 98.7
1613000 59쪽 〃 28.8 96.0 95.8
1613000 85쪽 〃 24.3 99.7 99.7
80168 61쪽 pdf/80168_regulatory_analysis-hwp-2024.pdf 99.0 99.0 98.8
1613000 198쪽 pdf/1613000-202200037-air-traffic-controller-cbta-2020.pdf 49.6 99.8 99.8
1613000 124쪽 〃 82.1 99.3 99.3
1613000 125쪽 〃 27.9 99.5 99.5
1480000 22쪽 pdf/issue5941-1480000-201900698-2020.pdf 30.5 (206쪽, 1–30쪽만) 99.8 99.9
21761835 2쪽 pdf/task2146/21761835_jeonjik_exemption_table-2020.pdf 82.4 96.4 96.6
21761835 3쪽 〃 54.6 96.0 96.3
1613000 127쪽 pdf/1613000-202200037-air-traffic-controller-cbta-2020.pdf 52.0 99.9 99.7
1613000 128쪽 〃 50.8 98.0 97.9
1613000 144쪽 〃 93.4 99.9 99.9
1613000 154쪽 〃 96.1 99.9 99.9
1613000 195쪽 〃 96.7 99.8 99.8
1613000 196쪽 〃 60.8 99.9 99.9
1613000 201쪽 〃 55.5 98.5 98.3
17253153 3쪽 pdf/17253153-traffic-safety-designated-routes-2020.pdf 87.3 100.0 100.00
80168 5쪽 pdf/80168_regulatory_analysis-hwp-2024.pdf 80.0 99.97 99.9
issue1853 16쪽 pdf/issue1853_caption_precedes_body_split-hwpx-2020.pdf 83.9 99.8 99.3
1342000 31쪽 mydocs/pr/assets/issue7445/education-curriculum-map/existing-hwp-hancom2020-print.pdf (420쪽 — 비교 불가) 99.8 99.8
1342000 199쪽 〃 (420쪽 — 비교 불가) 99.95 99.98
1342000 200쪽 〃 (420쪽 — 비교 불가) 99.95 99.9
1342000 202쪽 〃 (420쪽 — 비교 불가) 97.2 96.9
1342000 203쪽 〃 (420쪽 — 비교 불가) 99.9 99.9
1342000 189쪽 〃 (420쪽 — 비교 불가) 98.0 98.1
1342000 126쪽 〃 (420쪽 — 비교 불가) 99.4 99.4
1342000 127쪽 〃 (420쪽 — 비교 불가) 99.4 99.3
1342000 51쪽 〃 (420쪽 — 비교 불가) 99.9 99.9
1342000 56쪽 〃 (420쪽 — 비교 불가) 98.6 98.5
1342000 59쪽 〃 (420쪽 — 비교 불가) 99.80 99.97
1342000 61쪽 〃 (420쪽 — 비교 불가) 99.78 99.97
1342000 62쪽 〃 (420쪽 — 비교 불가) 99.84 99.97
1342000 307쪽 〃 (420쪽 — 비교 불가) 99.95 99.97
1342000 250쪽 〃 (420쪽 — 비교 불가) 99.62 99.67
1342000 251쪽 〃 (420쪽 — 비교 불가) 97.98 97.85
#8105 빈 띠 픽스처 2·4·6·8·10·12쪽 pdf/issue8105/declared_row_band-2024.pdf(한컴 2024) — 100.0 100.0
hwpx_sample2 6쪽 pdf/hwpx_sample2-hwp-2024.pdf(한컴 2024) — 99.8 99.99
hwpx_sample2 7쪽 〃 — 99.7 99.99
issue5169 4쪽 pdf/issue7674/issue5169_viewtext_changetracking-2020.pdf 97.2 99.97 99.97
휴먼명조 condense 끝 줄 사다리 1쪽 pdf/issue7702/humanmyeongjo_condense_end_fine-2024.pdf(한컴 2024) 54.1 99.9 99.9
휴먼명조 ASCII 사다리 10pt 자간 −10% 1쪽 pdf/issue7702/humanmyeongjo_ascii_10pt_m10-2024.pdf(한컴 2024) 99.3 99.8 99.7
1613000 186쪽 pdf/1613000-202200037-air-traffic-controller-cbta-2020.pdf 43.1 99.4 99.4
1613000 188쪽 〃 30.3 99.3 99.3
issue1880 1쪽 pdf/issue1880/issue1880_takeplace_host_before-2024.pdf 99.9 99.9 99.9
1613000 191쪽 pdf/1613000-202200037-air-traffic-controller-cbta-2020.pdf 44.3 99.9 99.8
1613000 192쪽 〃 44.7 99.5 99.6

(2px 이웃 관용 내용 실루엣 일치율, 96dpi. 80168 61쪽·issue1880 1쪽은 devel 이 이미 같은 값 — 그 사이 devel 에 같은 계열 수정이 들어갔다.)

1613000 58쪽 · 기준 PDF p58 ↔ rhwp p58 — 1×1 상자가 중첩 11×4 표의 저장 첫 조각 경계 [32] 에서 갈림 · 22×2 표 왼쪽 앵커

출력 review overlay
Native 1613000 p58 Native review 1613000 p58 Native overlay
fresh WASM 1613000 p58 fresh WASM review 1613000 p58 fresh WASM overlay

Native 98.66 / WASM 98.72.

1613000 59쪽 · 기준 PDF p59 ↔ rhwp p59 — 3행부터 이어받고 뒤 문단이 저장 줄

출력 review overlay
Native 1613000 p59 Native review 1613000 p59 Native overlay
fresh WASM 1613000 p59 fresh WASM review 1613000 p59 fresh WASM overlay

Native 96.00 / WASM 95.83.

1613000 85쪽 · 기준 PDF p85 ↔ rhwp p85 — 84쪽 각주 아래 빈 문단이 84쪽에 남고 85쪽이 저장 줄에서 시작

출력 review overlay
Native 1613000 p85 Native review 1613000 p85 Native overlay
fresh WASM 1613000 p85 fresh WASM review 1613000 p85 fresh WASM overlay

Native 99.65 / WASM 99.68.

80168 61쪽 · 기준 PDF p61 ↔ rhwp p61 — 행 12 첫 문단에서 60쪽을 닫고 「하는 규제」부터

출력 review overlay
Native 80168hwp p61 Native review 80168hwp p61 Native overlay
fresh WASM 80168hwp p61 fresh WASM review 80168hwp p61 fresh WASM overlay

Native 98.98 / WASM 98.75.

1613000 198쪽 · 기준 PDF p198 ↔ rhwp p198 — 빈 구분 행 96 부터 — 197쪽은 본문 안에서 닫힘

출력 review overlay
Native 1613000 p198 Native review 1613000 p198 Native overlay
fresh WASM 1613000 p198 fresh WASM review 1613000 p198 fresh WASM overlay

Native 99.85 / WASM 99.84.

1613000 124쪽 · 기준 PDF p124 ↔ rhwp p124 — 이어받은 행 1 이 저장 재시작 [51,70] 에서 닫힘

출력 review overlay
Native 1613000 p124 Native review 1613000 p124 Native overlay
fresh WASM 1613000 p124 fresh WASM review 1613000 p124 fresh WASM overlay

Native 99.32 / WASM 99.32.

1613000 125쪽 · 기준 PDF p125 ↔ rhwp p125 — 오른칸 32번째 문단 통째 · 캡션 아래 빈 호스트 뒤 문단이 저장 줄

출력 review overlay
Native 1613000 p125 Native review 1613000 p125 Native overlay
fresh WASM 1613000 p125 fresh WASM review 1613000 p125 fresh WASM overlay

Native 99.49 / WASM 99.48.

1480000 22쪽 · 기준 PDF p22 ↔ rhwp p22

출력 review overlay
Native 1480000 p22 Native review 1480000 p22 Native overlay
fresh WASM 1480000 p22 fresh WASM review 1480000 p22 fresh WASM overlay

Native 99.79 / WASM 99.87.

21761835 2쪽 · 기준 PDF p2 ↔ rhwp p2

출력 review overlay
Native 21761835 p2 Native review 21761835 p2 Native overlay
fresh WASM 21761835 p2 fresh WASM review 21761835 p2 fresh WASM overlay

Native 96.35 / WASM 96.62.

21761835 3쪽 · 기준 PDF p3 ↔ rhwp p3 — 쪽 끝 띠 · 걸침 총높이 보존

출력 review overlay
Native 21761835 p3 Native review 21761835 p3 Native overlay
fresh WASM 21761835 p3 fresh WASM review 21761835 p3 fresh WASM overlay

Native 96.03 / WASM 96.29.

1613000 127쪽 · 기준 PDF p127 ↔ rhwp p127 — 저장 재시작 컷 끝 행 = 컷 내용 96.6px

출력 review overlay
Native 1613000 p127 Native review 1613000 p127 Native overlay
fresh WASM 1613000 p127 fresh WASM review 1613000 p127 fresh WASM overlay

Native 99.87 / WASM 99.71.

1613000 128쪽 · 기준 PDF p128 ↔ rhwp p128 — 끝 조각 캡션 간격 = 통째 표

출력 review overlay
Native 1613000 p128 Native review 1613000 p128 Native overlay
fresh WASM 1613000 p128 fresh WASM review 1613000 p128 fresh WASM overlay

Native 98.02 / WASM 97.89.

1613000 144쪽 · 기준 PDF p144 ↔ rhwp p144 — 통째 끝 행 139 = 행 높이, 띠 없음

출력 review overlay
Native 1613000 p144 Native review 1613000 p144 Native overlay
fresh WASM 1613000 p144 fresh WASM review 1613000 p144 fresh WASM overlay

Native 99.93 / WASM 99.92.

1613000 154쪽 · 기준 PDF p154 ↔ rhwp p154 — 내용 컷 끝 행 51 = 닫는 선

출력 review overlay
Native 1613000 p154 Native review 1613000 p154 Native overlay
fresh WASM 1613000 p154 fresh WASM review 1613000 p154 fresh WASM overlay

Native 99.93 / WASM 99.93.

1613000 195쪽 · 기준 PDF p195 ↔ rhwp p195 — 행 43 상자 = 닫는 선 713.03px

출력 review overlay
Native 1613000 p195 Native review 1613000 p195 Native overlay
fresh WASM 1613000 p195 fresh WASM review 1613000 p195 fresh WASM overlay

Native 99.80 / WASM 99.81.

1613000 196쪽 · 기준 PDF p196 ↔ rhwp p196 — 195쪽 행 43 을 닫는 선에서 닫고 행 44 부터

출력 review overlay
Native 1613000 p196 Native review 1613000 p196 Native overlay
fresh WASM 1613000 p196 fresh WASM review 1613000 p196 fresh WASM overlay

Native 99.93 / WASM 99.93.

1613000 201쪽 · 기준 PDF p201 ↔ rhwp p201 — 75×3 표 행 43 부터

출력 review overlay
Native 1613000 p201 Native review 1613000 p201 Native overlay
fresh WASM 1613000 p201 fresh WASM review 1613000 p201 fresh WASM overlay

Native 98.47 / WASM 98.30.

17253153 3쪽 · 기준 PDF p3 ↔ rhwp p3 — 분할 행 칸 정렬

출력 review overlay
Native 17253153 p3 Native review 17253153 p3 Native overlay
fresh WASM 17253153 p3 fresh WASM review 17253153 p3 fresh WASM overlay

Native 100.00 / WASM 100.00.

80168 5쪽 · 기준 PDF p5 ↔ rhwp p5

출력 review overlay
Native 80168hwp p5 Native review 80168hwp p5 Native overlay
fresh WASM 80168hwp p5 fresh WASM review 80168hwp p5 fresh WASM overlay

Native 99.97 / WASM 99.94.

issue1853 16쪽 · 기준 PDF p16 ↔ rhwp p16

출력 review overlay
Native issue1853hwpx p16 Native review issue1853hwpx p16 Native overlay
fresh WASM issue1853hwpx p16 fresh WASM review issue1853hwpx p16 fresh WASM overlay

Native 99.78 / WASM 99.32.

1342000 31쪽 · 기준 PDF p31 ↔ rhwp p31 — 분할 행 칸 정렬

출력 review overlay
Native 1342000 p31 Native review 1342000 p31 Native overlay
fresh WASM 1342000 p31 fresh WASM review 1342000 p31 fresh WASM overlay

Native 99.82 / WASM 99.83.

1342000 202쪽 · 기준 PDF p202 ↔ rhwp p202 — 쪽 수 원인이던 행 92 — 선언 97.1px(PDF 97.25), 마지막 행 둘째 줄 202쪽

출력 review overlay
Native 1342000 p202 Native review 1342000 p202 Native overlay
fresh WASM 1342000 p202 fresh WASM review 1342000 p202 fresh WASM overlay

Native 97.24 / WASM 96.86.85 (478da8250 전 92.28 / 92.40).

1342000 199쪽 · 기준 PDF p199 ↔ rhwp p199 — 끝 행 63 c4 는 저장 재시작 특성 에서 갈리고, 같은 행에서 끝나는 걸침 칸 r62 c8 셋째 줄은 닫는 선 안에 남음

출력 review overlay
Native 1342000 p199 Native review 1342000 p199 Native overlay
fresh WASM 1342000 p199 fresh WASM review 1342000 p199 fresh WASM overlay

Native 98.71 / WASM 98.62.

1342000 200쪽 · 기준 PDF p200 ↔ rhwp p200 — 행 63 이어지는 조각 16px(PDF 16.1) · 행 75 선언 높이로 쪽 끝

출력 review overlay
Native 1342000 p200 Native review 1342000 p200 Native overlay
fresh WASM 1342000 p200 fresh WASM review 1342000 p200 fresh WASM overlay

Native 99.95 / WASM 99.94.

1342000 203쪽 · 기준 PDF p203 ↔ rhwp p203 — 202쪽 마지막 행의 둘째 줄이 넘어오지 않음

출력 review overlay
Native 1342000 p203 Native review 1342000 p203 Native overlay
fresh WASM 1342000 p203 fresh WASM review 1342000 p203 fresh WASM overlay

Native 99.94 / WASM 99.91.

1342000 189쪽 · 기준 PDF p189 ↔ rhwp p189 — [9체01-04] 칸 …실천한 / 다. 세 줄(#7702)

출력 review overlay
Native 1342000 p189 Native review 1342000 p189 Native overlay
fresh WASM 1342000 p189 fresh WASM review 1342000 p189 fresh WASM overlay

Native 97.97 / WASM 98.11.

1342000 126쪽 · 기준 PDF p126 ↔ rhwp p126 — noAdjust 표 걸침 칸 끝 행 60 = 선언 2982HU, 쪽 끝 «자전거를 탈 때» 줄까지 (#8101)

출력 review overlay
Native 1342000 p126 Native review 1342000 p126 Native overlay
fresh WASM 1342000 p126 fresh WASM review 1342000 p126 fresh WASM overlay

Native 99.44 / WASM 99.40.

1342000 127쪽 · 기준 PDF p127 ↔ rhwp p127 — «현장체험학습 시 버스 이용» 으로 시작

출력 review overlay
Native 1342000 p127 Native review 1342000 p127 Native overlay
fresh WASM 1342000 p127 fresh WASM review 1342000 p127 fresh WASM overlay

Native 99.40 / WASM 99.34.

1342000 51쪽 · 기준 PDF p51 ↔ rhwp p51 — 구역 1 표 이어지는 조각 윗변 = 본문 위 + 141HU (#8105)

출력 review overlay
Native 1342000 p51 Native review 1342000 p51 Native overlay
fresh WASM 1342000 p51 fresh WASM review 1342000 p51 fresh WASM overlay

Native 99.88 / WASM 99.91.

1342000 56쪽 · 기준 PDF p56 ↔ rhwp p56 — 55쪽이 행 21 p0·p1 을 담고 56쪽이 p2 «제10조» 로 시작 (#8105)

출력 review overlay
Native 1342000 p56 Native review 1342000 p56 Native overlay
fresh WASM 1342000 p56 fresh WASM review 1342000 p56 fresh WASM overlay

Native 98.55 / WASM 98.53.

1342000 59쪽 · 기준 PDF p59 ↔ rhwp p59 — 58쪽 «부산» 행 9 의 남은 선언 25.9px 가 첫머리 빈 띠 (#8105)

출력 review overlay
Native 1342000 p59 Native review 1342000 p59 Native overlay
fresh WASM 1342000 p59 fresh WASM review 1342000 p59 fresh WASM overlay

Native 99.80 / WASM 99.97. 수정 전 44.5(띠를 버려 쪽 전체가 19.4pt 위).

1342000 61쪽 · 기준 PDF p61 ↔ rhwp p61 — 첫 빈 띠 51.6px = 행 8–17 병합 칸의 남은 선언 (#8105)

출력 review overlay
Native 1342000 p61 Native review 1342000 p61 Native overlay
fresh WASM 1342000 p61 fresh WASM review 1342000 p61 fresh WASM overlay

Native 99.78 / WASM 99.97. 수정 전 50.0(행 17 꼬리 30.8px 로 시작).

1342000 62쪽 · 기준 PDF p62 ↔ rhwp p62

출력 review overlay
Native 1342000 p62 Native review 1342000 p62 Native overlay
fresh WASM 1342000 p62 fresh WASM review 1342000 p62 fresh WASM overlay

Native 99.84 / WASM 99.97. 수정 전 49.2.

1342000 307쪽 · 기준 PDF p307 ↔ rhwp p307 — 가로 쪽 첫머리 빈 띠 (#8105)

출력 review overlay
Native 1342000 p307 Native review 1342000 p307 Native overlay
fresh WASM 1342000 p307 fresh WASM review 1342000 p307 fresh WASM overlay

Native 99.95 / WASM 99.97. 수정 전 73.4.

1342000 250쪽 · 기준 PDF p250 ↔ rhwp p250 — 행 49 번호 문단 …갈등 현상 탐색하기 한 줄 · 행 49 = 선언 3882HU 51.9px (#8105)

출력 review overlay
Native 1342000 p250 Native review 1342000 p250 Native overlay
fresh WASM 1342000 p250 fresh WASM review 1342000 p250 fresh WASM overlay

Native 99.62 / WASM 99.67. 수정 전 78.6(행 49 가 저장 줄 …탐색하 / 기 두 줄로 69.1px, 그 아래 행이 모두 17.2px 내려감). overlay 에서 행 경계가 모두 PDF 괘선과 겹친다.

1342000 251쪽 · 기준 PDF p251 ↔ rhwp p251 — 250쪽 행 높이 복귀 뒤 이어지는 행

출력 review overlay
Native 1342000 p251 Native review 1342000 p251 Native overlay
fresh WASM 1342000 p251 fresh WASM review 1342000 p251 fresh WASM overlay

Native 97.98 / WASM 97.85. 수정 전 69.8.

#8105 픽스처 2쪽 · 한컴 2024 PDF p2 ↔ rhwp p2 — 저장 줄 + 병합 칸, D 15862: 남은 선언 51.2px 띠

출력 review overlay
Native issue8105-declared-row-band p2 Native review issue8105-declared-row-band p2 Native overlay
fresh WASM issue8105-declared-row-band p2 fresh WASM review issue8105-declared-row-band p2 fresh WASM overlay

Native·WASM 100.0.

#8105 픽스처 4쪽 · 한컴 2024 PDF p4 ↔ rhwp p4 — D 14738: 남은 선언 ≤ 1282HU 흡수, «다음» 행으로 시작

출력 review overlay
Native issue8105-declared-row-band p4 Native review issue8105-declared-row-band p4 Native overlay
fresh WASM issue8105-declared-row-band p4 fresh WASM review issue8105-declared-row-band p4 fresh WASM overlay

Native·WASM 100.0.

#8105 픽스처 10쪽 · 한컴 2024 PDF p10 ↔ rhwp p10 — 재조판 칸, D 14738: 흡수(수정 전 rhwp 는 15px 띠)

출력 review overlay
Native issue8105-declared-row-band p10 Native review issue8105-declared-row-band p10 Native overlay
fresh WASM issue8105-declared-row-band p10 fresh WASM review issue8105-declared-row-band p10 fresh WASM overlay

Native·WASM 100.0. 6·8·12쪽도 100.0(TSV).

hwpx_sample2 6쪽 · 한컴 2024 PDF p6 ↔ rhwp p6 — 미뤄진 첫 조각: 오프셋 소진, 윗변 = 본문 위 + 283HU, 아래 = 저장 첫 프레임 (#8105)

출력 review overlay
Native hwpx_sample2 p6 Native review hwpx_sample2 p6 Native overlay
fresh WASM hwpx_sample2 p6 fresh WASM review hwpx_sample2 p6 fresh WASM overlay

Native 99.81 / WASM 99.99.

hwpx_sample2 7쪽 · 한컴 2024 PDF p7 ↔ rhwp p7 — 이어지는 조각 행 경계 294.4px (#8105)

출력 review overlay
Native hwpx_sample2 p7 Native review hwpx_sample2 p7 Native overlay
fresh WASM hwpx_sample2 p7 fresh WASM review hwpx_sample2 p7 fresh WASM overlay

Native 99.67 / WASM 99.99.

issue5169 4쪽 · 기준 PDF p4 ↔ rhwp p4 — …장기목표에 / 반영하는

출력 review overlay
Native issue5169 p4 Native review issue5169 p4 Native overlay
fresh WASM issue5169 p4 fresh WASM review issue5169 p4 fresh WASM overlay

Native 99.97 / WASM 99.97.

휴먼명조 condense 끝 줄 사다리 1쪽 · 한컴 2024 — 폭 26705+d HU, d ≤ 6 은 다. 셋째 줄 · d ≥ 7 은 붙음

출력 review overlay
Native humanmyeongjo-condense-fine p1 Native review humanmyeongjo-condense-fine p1 Native overlay
fresh WASM humanmyeongjo-condense-fine p1 fresh WASM review humanmyeongjo-condense-fine p1 fresh WASM overlay

Native 99.94 / WASM 99.87.

휴먼명조 ASCII 사다리 10pt 자간 −10% 1쪽 · 한컴 2024 — 가c × 20

출력 review overlay
Native humanmyeongjo-ascii-10pt-m10 p1 Native review humanmyeongjo-ascii-10pt-m10 p1 Native overlay
fresh WASM humanmyeongjo-ascii-10pt-m10 p1 fresh WASM review humanmyeongjo-ascii-10pt-m10 p1 fresh WASM overlay

Native 99.78 / WASM 99.70.

1613000 186쪽 · 기준 PDF p186 ↔ rhwp p186 — 26행 둘째 줄 이어받기 · 빈 문단 저장 줄 · pi=4 21행까지

출력 review overlay
Native 1613000 p186 Native review 1613000 p186 Native overlay
fresh WASM 1613000 p186 fresh WASM review 1613000 p186 fresh WASM overlay

Native 99.35 / WASM 99.44.

1613000 188쪽 · 기준 PDF p188 ↔ rhwp p188 — 과목 3 제목 뒤 pi=7 첫 조각

출력 review overlay
Native 1613000 p188 Native review 1613000 p188 Native overlay
fresh WASM 1613000 p188 fresh WASM review 1613000 p188 fresh WASM overlay

Native 99.27 / WASM 99.29.

issue1880 1쪽 · 기준 PDF p1 ↔ rhwp p1 — 첫 조각 원점 = 문단 윗변 + 오프셋

출력 review overlay
Native issue1880 p1 Native review issue1880 p1 Native overlay
fresh WASM issue1880 p1 fresh WASM review issue1880 p1 fresh WASM overlay

Native 99.93 / WASM 99.95.

1613000 191쪽 · 기준 PDF p191 ↔ rhwp p191 — 새 쪽 첫 표 뒤 빈 문단 저장 줄 · pi=11 첫 조각 행 0–4

출력 review overlay
Native 1613000 p191 Native review 1613000 p191 Native overlay
fresh WASM 1613000 p191 fresh WASM review 1613000 p191 fresh WASM overlay

Native 99.87 / WASM 99.84.

1613000 192쪽 · 기준 PDF p192 ↔ rhwp p192 — pi=11 행 5 부터

출력 review overlay
Native 1613000 p192 Native review 1613000 p192 Native overlay
fresh WASM 1613000 p192 fresh WASM review 1613000 p192 fresh WASM overlay

Native 99.54 / WASM 99.57.

전쪽 TSV (90% 미만 쪽 수)

mydocs/pr/assets/devel_table_scan_regression/tsv/ 에 문서별 devel(efc52afb7)·브랜치 Native·브랜치 fresh WASM TSV 를 넣었다(브랜치는 code head 9f2b24150 — 1342000 만 이 head 에서 바뀌었고, 다른 문서는 다시 찍은 TSV 가 직전 head 와 같다). 36382669·issue5169·휴먼명조 합성 입력의 devel 열은 같은 base 바이너리, 합성 coarse·ASCII 10pt·13pt 는 직전 head 478da8250 값이다.

문서 쪽 수 rhwp/PDF devel 브랜치 Native 브랜치 WASM TSV
1480000-201900698 205/205 비교 불가(devel 206쪽) — 1–30쪽 14 21 (최저 16.0) 21 (최저 16.6) Native · WASM · devel 1–30
21761835 6/6 3 (최저 39.5) — 2쪽 82.4, 3쪽 54.6, 4쪽 39.5 0 (최저 96.0) 0 (최저 96.3) Native · WASM · devel
1613000-202200037 204/204 24 (최저 24.3) 3 (최저 30.4) — 1쪽 88.7, 6쪽 89.9, 23쪽 30.4 2 (최저 29.2) — 1쪽 86.6, 23쪽 29.2 Native · WASM · devel
17253153 5/5 1 (최저 87.3) — 3쪽 87.3 0 (최저 94.9) 0 (최저 94.4) Native · WASM · devel
80168 157/157 8 (최저 37.4) 7 (최저 37.4) 7 (최저 37.4) Native · WASM · devel
issue1853 52/52 4 (최저 14.3) — 16쪽 83.9, 41쪽 54.2, 48쪽 36.2, 49쪽 14.3 0 (최저 93.3) 0 (최저 94.2) Native · WASM · devel
1342000 415/415 비교 불가(devel 420쪽) 97 (최저 30.8) 97 (최저 31.2) Native · WASM
#8105 빈 띠 픽스처 (한컴 2024) 12/12 — 0 (최저 100.0) 0 (최저 100.0) Native · WASM
issue1880 (한컴 2024) 10/10 0 (최저 94.4) 0 (최저 97.7) 0 (최저 98.0) Native · WASM · devel
70833 (띠 반례) 18/18 5 (최저 49.9) 5 (최저 49.9) 5 (최저 49.1) Native · WASM · devel
36382669 (한컴 2024, #7702 영향) 8/8 2 (최저 36.6) 2 (최저 36.6) 2 (최저 35.7) Native · WASM
issue5169 (#7702 영향) 6/6 0 (최저 97.2) 0 (최저 99.5) 0 (최저 98.5) Native · WASM
휴먼명조 condense 끝 줄 사다리 fine (한컴 2024) 2/2 2 (최저 40.7) 0 (최저 99.9) 0 (최저 99.9) Native · WASM
휴먼명조 condense 끝 줄 사다리 coarse (한컴 2024) 2/2 (478da8250) 2 (최저 45.8) 0 (최저 100.0) 0 (최저 99.9) Native · WASM
휴먼명조 ASCII 사다리 10pt (한컴 2024) 3/3 (478da8250) 0 (최저 99.2) 0 (최저 99.7) 0 (최저 99.6) Native · WASM
휴먼명조 ASCII 사다리 10pt 자간 −10% (한컴 2024) 3/3 (478da8250) 0 (최저 99.3) 0 (최저 99.8) 0 (최저 99.7) Native · WASM
휴먼명조 ASCII 사다리 13pt (한컴 2024) 4/4 (478da8250) 0 (최저 98.1) 0 (최저 99.4) 0 (최저 99.3) Native · WASM

템플릿 기준(한 쪽이라도 90% 미만이면 재검토)에 미달한다. 남은 90% 미만 쪽은 이 PR 전부터 있던 쪽이다. devel 과 쪽 수가 같은 7개 문서에서 브랜치가 devel 보다 0.3 넘게 낮은 쪽 0, 새로 90% 아래로 내린 쪽 0(오른 쪽 1613000 45·issue1853 4·21761835 3·나머지 각 1). 1613000 의 6쪽 89.9·23쪽 30.4 와 1쪽 88.7 은 devel 과 같은 값이다(리베이스 뒤 devel 쪽에서 생긴 차이). 1480000·1342000 은 devel 쪽 수가 달라(206·420쪽) 전쪽 비교가 안 된다. 36382669 의 1쪽 80.3·8쪽 36.6 은 devel 과 같은 값이다(#7702 수정이 바꾼 5–7쪽은 0.3 이내).

테스트

  • 변경 범위: Rust(조판) + 문서 증적
  • 검증 commit 9f2b24150(lint·nextest 는 커밋 직전 같은 트리), 정책 비교 base 2e3b4f880(= 최신 devel)
  • node scripts/rust-test-suite-manifest.mjs --prepare → cargo fmt --all -- --check → native Clippy → WASM32 -p rhwp --lib Clippy → workspace build → workspace all-targets Clippy -D warnings → manifest --check --base-ref 2e3b4f880: LINT_OK
  • cargo nextest run --cargo-profile release-test --tests: 11076 passed / 0 failed (45 skipped). 직전 51a628363 은 11074/0, e64b513ed 는 11071/0 (새 테스트 파일은 실행 뒤 rustfmt 공백만 바뀜 — 그 뒤 lint 묶음 LINT_OK). 직전 1cf3b879b 은 11067/0, f296dbc21 은 11064/0(rustfmt 전 공백만 다른 트리에서 실행), 478da8250 은 11062/0. 리베이스 직후(f8fa0f02a)에는 11053 passed / 1 failed(rows_inside_a_crossing_rowspan_still_split_after_one_line) — 065125a94 로 해소
  • node scripts/rust-unit-test-tiers.mjs --check --base-ref 2e3b4f880: 통과
  • fresh WASM: 저장소 루트에서 CARGO_TARGET_DIR=target/pr-review scripts/wasm-pack-locked.sh --target web --out-dir pkg → pkg/rhwp_bg.wasm = rhwp-studio/public/rhwp_bg.wasm SHA-256 c4ed9986…
  • 9f2b24150 A/B(51a628363 대비, 1342000 전쪽 Native·fresh WASM): 쪽 수 415 그대로, 바뀐 쪽 38 — 상승 33, 하락 5, 90% 미만 123→97(새로 90% 아래로 간 쪽 0). 250쪽 78.6→99.6·251쪽 69.8→98.0, 357–371·282–288·177·232·235쪽 90% 이상 복귀. 하락: 175쪽 84.4→82.8, 272쪽 70.4→67.6, 273쪽 71.3→67.7, 274쪽 75.9→71.7, 359쪽 74.4→70.0(WASM 같은 방향, 82.7·66.2·66.5·70.7·68.3). 175쪽은 새 줄 나눔이 꼬리를 붙이는 경계 근접 문단, 272–274·359쪽은 행 높이가 정본과 같아진 뒤 남은 기존 쪽 끝 분할 한 줄 차이의 연쇄다. 59·60쪽(번호 없는 …제 / 정] 반례)은 99.8 그대로. 샘플 전수(1,517개): 넓힌 조건이 실제로 줄을 바꾸는 문서는 1342000·interview.hwp 뿐이고 interview 출력은 바이트 동일. 다른 증적 문서의 전쪽 TSV 는 직전 head 와 같다
  • 9f2b24150 근거(한/글 2024 13.0.0.3901 MCP 직접 조판, 생성기 mydocs/tech/investigations/issue-8105/probes/make_numbered_stale_tail.py, 입력·PDF 같은 폴더): 1×1 표 칸 문단의 저장 줄이 끝 음절 기 만 둘째 줄로 보내는 15가지 변형. HWP5(rhwp convert) 입력에서 «-»·«1.» 번호를 그린 문단은 모두 한 줄, 번호 없는 문단은 저장 줄 폭이 칸과 같으면 두 줄, 1HU 라도 다르면 한 줄. 줄 flags(0x200000·0x100000)·appVersion(2014·2020)은 결과를 바꾸지 않는다. HWPX 입력에서는 한/글이 덧붙인 «-» 번호를 그리지 않아 그 행은 근거에서 뺐다. 1342000 정본(한/글 2020 Print)도 번호 문단 꼬리 39/40 을 붙이고 번호 없는 …제|정]·…일|부개정] 은 두 줄이다
  • 478da8250 A/B(065125a94 대비, 샘플 1,252 SVG + 9개 문서 전쪽 TSV): SVG 가 바뀐 샘플은 1613000 139·140쪽뿐(99.2→99.3, 99.6→99.9). 1342000 은 바뀐 쪽 12 모두 상승 — 200쪽 92.8→99.95, 202쪽 92.3→97.3, 203쪽 91.8→99.9, 84쪽 30.4→50.8, 82쪽 42.8→51.2, 54쪽 77.4→78.8 등(WASM 도 같은 방향). 하락 쪽 0
  • 51a628363 A/B(e64b513ed 대비): 샘플 SVG 13,408쪽 중 바뀐 문서 4개 — 1480000-201900698 45쪽 98.2→99.9, 18095317 6쪽 상승, 21761835 5·6쪽 ±0.03, vietnam_labor_report 41쪽(PDF 없음, 칸 clip 높이 +4.8px 만 — 보이는 이동 없음). 1342000 전쪽: 90% 미만 126→123, 59쪽 44.5→99.8·61쪽 50.0→99.8·62쪽 49.2→99.8·307쪽 73.4→100, 25–28·175·198·199·303·321·330·334·342쪽 소폭 상승. 하락: 250쪽 84.6→78.6·251쪽 98.0→69.8·352쪽 66.7→63.2 — 250쪽 첫머리 새 17.2px 띠는 PDF 에도 있다(맞음). 하락은 기존 불일치가 드러난 것: 250쪽 중간 한 행이 rhwp 69.1px ↔ PDF 51.9px, 351쪽 반복 머리 행 45.2 ↔ 18.0px. 중간 변형(블록 컷 조각까지 병합 칸 몫 확장)은 1341000 29쪽 92.1→87.6 이라 내용이 끝난 행으로 좁혔다(29쪽 기준선 복귀).
  • 51a628363 근거(한/글 2024 13.0.0.3901 MCP 직접 조판, 생성기 mydocs/tech/investigations/issue-8105/probes/make_declared_row_band.py): 시험 행 선언 D 사다리에서 다음 쪽 첫 행 = D − 그린 높이 > 1282HU 일 때만 빈 띠(17.0px 흡수·17.2px 이월). 칸 여백·표 기본 여백·글자 크기·저장 줄·병합 칸을 바꿔도 문턱 불변. 한/글 2020 1342000 의 13.33 흡수·21.33 이월과도 맞는다.
  • e64b513ed A/B(1cf3b879b 대비): 샘플 1,252 SVG 중 바뀐 문서 10개·14쪽, 쪽 수 변화 0. PDF 대조 — hwpx_sample2 hwp 6·7쪽 98.7/96.7 → 99.8/99.7, hwpx 6쪽 74.9 → 99.8, 75544 hwpx 31·32쪽 86.7/53.3 → 99.9/97.3, 1480000 41쪽 71.1 → 100.0, 59043 24쪽 −0.1, 70833 13쪽 +0.1. PDF 없는 156555538(자리차지 표가 다음 쪽으로 넘어갈 때 문단 기준 세로 오프셋(146.7mm)을 그대로 더해 쪽 상단이 비고 표가 갈라짐 (156555538 9쪽) #6143 근거)·issue2439 는 한/글 2024 MCP 로 변환해 대조: 156555538 17쪽 = 변환본, 9쪽 윗변 77.44px = 변환본(수정 전과 같음). issue2439(rhwp 11 / 변환본 10쪽, 기존 불일치) 3쪽 54.9 → 90% 이상, 4쪽 47.9 → 33.1 — 3·4쪽 행 경계는 변환본과 같아졌고 4쪽은 끝 조각 뒤 다음 표까지 간격(+13px, 이 변경 조건 밖의 기존 오차)이 드러난다. 1342000(Native/WASM 같음) 90% 미만 132 → 126, 하락 0: 26–34쪽 +2~+13, 51쪽 +55, 53–57쪽 +20~+38
  • e64b513ed 근거: ① 1342000 구역 1 표(오프셋 5280·752HU) 한/글 2020 이어지는 조각 윗변 26–29·31·34·55쪽 본문 위 + 141HU(±0.1pt). ② 55쪽 행 21 칸 저장 vpos p0 0 · p1 1800 · p2 500(앞 간격 500) — 한/글은 p0·p1 을 34.66pt 조각에 담는다; rhwp 단위 p1 = 앞 간격 6.67 + 줄 13.33 + 뒤 줄간격 4.0px, 예산 39.95px. ③ hwpx_sample2 표 pi=69: 앵커 1016.48 + 오프셋 4.0 뒤 26.4px < 0행(한 줄) 28.41px — 한/글 2024 6쪽 윗변 41.6px = 본문 위 + 283HU, 첫 조각 1037.88px = 저장 첫 프레임 1038.01px. 종전 예산은 오프셋 4.0 과 여백 3.8 을 둘 다 빼 1034.0px 로 닫았다. 그리기에서 유효 오프셋에 여백을 직접 더한 중간 변형은 156555538 9쪽(이미 다른 규칙이 여백을 엶)에서 여백을 두 번 열어 99.4 → 94.2 — OR 묶음으로 바꿨다
  • 1cf3b879b A/B(f296dbc21 대비): 샘플 1,252 SVG 중 바뀐 문서 17개·63쪽, 쪽 수 변화 0. PDF 가 있는 15개 대조에서 0.3 넘게 내린 쪽은 sample1-repro 39·40쪽(−0.5)뿐, 편람 hwp 50·160쪽 +0.30.4. 1342000(Native/WASM 같은 방향): 126쪽 86.4→99.4, 127쪽 76.9→99.4, 128쪽 76.9→94.8, 129쪽 77.4→96.8, 101쪽 +2.8, 210쪽 +6.7, 90% 미만 136→132. 내린 쪽은 기존 저점 68·69·143·144·365쪽(−0.3−0.8). 그 밖 PR 8문서·합성 입력 TSV 바이트 동일
  • 1cf3b879b 근거: 한/글 2020 Print 1342000 쪽 끝 표 아래 괘선(가로 쪽 척도 ×1.00047, 세로 ×1.00106 을 걷은 값) — noAdjust 표(구역 5 pi=8 0x0600000e, 구역 4 pi=12, 구역 6 pi=11, 구역 1 pi=3) 121·99·170·49쪽이 본문 아래 − 바깥 아래 여백에 −0.15·−0.14·−0.14·−0.03px, noAdjust 아닌 표 157·213·108·37쪽이 그 선 − 100HU 에 ±0.3px. 1613000(pi=1·pi=5, 0x04000006)의 기존 닫는 선 근거는 noAdjust 아닌 표라 그대로
  • f296dbc21 A/B(478da8250 대비): 샘플 약 130개 문서 export-text 중 줄바꿈이 바뀐 문서는 1342000(189쪽)·36382669(5·6·7쪽)·issue5169(4쪽) 셋, 쪽 수 변화 0. 바뀐 줄은 모두 한/글 PDF 와 같아짐 — 1342000 189쪽 …실천한 / 다.(한/글 2014 저장 줄·2020/2022/2024 PDF 공통), issue5169 4쪽 …장기목표에 / 반영하는(한/글 2020 PDF), 36382669 5쪽 67/45·6쪽 69/1·7쪽 69/52 글자 줄(한/글 2024 MCP 변환본, 이번에 pdf/issue7702/ 에 넣음). 9개 문서 전쪽 TSV: 0.3 넘게 바뀐 쪽은 1342000 189쪽 66.6→98.0(WASM 66.5→98.1) 하나, 그 밖 1,074쪽 하락 0(최대 ±0.3, 휴먼명조 ASCII 위치 이동). issue5169 4쪽 97.2→100.0. 합성 condense 사다리 40.7–58.2 → 99.9 이상
  • f296dbc21 근거(한/글 2024 MCP 직접 조판, 생성기·해시는 mydocs/tech/investigations/issue-7702/probes/): ① 189쪽 문단을 본문 폭만 26705+d HU 로 바꾼 사다리 — 한/글은 d ≤ 6 에서 다. 를 셋째 줄로, d ≥ 7 에서 붙임(수정 전 rhwp 는 d ≥ −37 에서 붙임). 붙은 줄에서 공백 8개가 줄어든 합 400HU 는 rhwp condense 모형·[layout] 1790387 67쪽 pi=14 — 저장 LineSeg 5줄을 그대로 써 한/글(2020·2024 모두 4줄)과 문단 높이가 갈린다, 67~70쪽 +26.4px · PR #7366 실루엣 미달 #7418 과 같음 ② 94자 가c × 20 사다리(10pt 자간 −10% / 10pt / 13pt) — 한/글 장치 전진폭이 HMKMM.TTF hmtx 와 94/94 같고 [layout/table/regression] PR #2309 셀 저장-ls1 재래핑 허용이 정합 분할표 문서 11건을 과다분할 회귀 (10k r16, 최대 +3쪽) #2430 표는 37·58·70자 다름 ③ 남는 28HU 는 문단 끝 . 의 자간 — 한/글은 양쪽 정렬 줄 끝 글자를 자간 없는 폭으로 상자에 맞춤(line_breaking: 자간 trim 이 fit-test 호출부 넷 중 하나에만 닿고 어느 테스트도 구속하지 않는다 #5678, issue7418 PDF 의 줄 끝 원점)
  • 리베이스 A/B: f8fa0f02a → 065125a94 샘플 1,252 SVG 바뀐 쪽 0(1342000 은 따로 대조 — 416→415쪽). 리베이스 전 head 21ab9623d 와 새 head 의 전수 A/B 는 devel 변경이 섞여 하지 않았고, 대표 30쪽·9개 문서 전쪽 TSV 를 새로 찍어 대신한다
  • 리베이스 전 단계별 A/B(해시는 리베이스 후 해시로 바꿈, 측정값은 그때 값):
    • a92d0d220: 1342000 31쪽 88.8→99.0, 17253153 3쪽 87.9→98.2, 70833 2쪽 95.4→99.0, 샘플 하락 0
    • 5994ce798: 샘플 중 21761835 만(2쪽 94.4→96.0, 3쪽 68.1→91.5), 1342000 81쪽 +4.2·82쪽 −0.85·83쪽 −0.3
    • b30e9e020(리베이스 head 대비): 1342000 416→415쪽, 바뀐 쪽 195 상승·20 하락(하락은 이전에 PDF 와 한 쪽 어긋난 채 비교되던 226–365쪽, 최대 −5.6), 새로 90% 이상 141쪽, 새로 90% 미만 0. 샘플은 fragment_ghost_vrules 18쪽 +0.8 만
    • 200beb58f(b30e9e020 대비, 샘플 1,252 SVG + 1342000): SVG 가 바뀐 문서는 1613000(185–191쪽 +37~+71), 59043 19쪽(45.5→90.8), table_scattered_header_rowbreak hwp·hwpx 51쪽(+0.96), issue1880(1쪽 +37.1, 2쪽 +0.08, 4쪽 −0.58 = 99.2→98.6), sample1-repro 20쪽(±0) 뿐. 90% 아래로 새로 내린 쪽 0. 1342000 SVG 동일. 중간 변형에서 나온 hwpspec 35쪽(표 40 을 쪽 끝에 가름 — 한/글은 통째 다음 쪽) 차이는 되감김 조건으로 없앴다
    • 23db8512f(7be2810a5 대비, 샘플 1,252 SVG + 1342000): SVG 가 바뀐 쪽은 1613000 123–125쪽뿐 — 123쪽 96.95→99.43, 124쪽 81.73→99.50, 125쪽 26.99→30.17(표는 맞고 뒤 본문 16px 차이가 남음 → 다음 커밋). 1342000 SVG 동일
    • 8c847d933(23db8512f 대비, 같은 범위): 0.3 넘게 바뀐 쪽은 issue1853 48쪽 34.26→95.82·49쪽 12.85→96.26, 1613000 125쪽 30.17→98.75 — 모두 상승. PDF 가 있는 그 밖 SVG 변화 쪽(편람 156, 86712, pr-1674, hwpx_sample2, 59043, 1341000, 1130000, 1480000-42, pic-in-head/table, synam, table_scattered_header, issue3236, 정책연구 등)은 Δ ±0.00. PDF 가 없는 문서는 한/글 2020 MCP 로 변환해 대조: task2070 은 72쪽부터 245쪽이 바뀌고 쪽 수 316→315 = 변환본 315쪽, 72–110쪽 평균 42.2(90% 미만 37쪽) → 99.77(0쪽), 전쪽 평균 97.00; 3112461 6쪽 99.63→99.44(아래 본문 1.87px 내려감 — PDF 글자 상자와의 거리는 변전소 줄 −1.6→+0.2, 배터리 줄 −1.1→+0.8 로 비슷), 156403546 16쪽 99.97→99.97; issue1891_external_bindata_link·1490000·1480000-201900698 은 부동소수 끝자리(827.6399…→827.64)만 다름. 중간 변형: 흐름 끝까지 상자 아래로 옮기면 issue1880 3·4쪽 −53·−65, 1613000 186–191쪽 −1−55(배제 띠가 뒤 문단을 밂), 빈 호스트 증거에 줄 상자 조건이 없으면 1613000 190–193쪽 −50−57(pi=8 이 빈 줄 감추기로 숨으며 흡수한 위 간격이 사라짐) — 둘 다 막았다
    • 2dfc0f184(8c847d933 대비, 샘플 1,252 SVG + 1342000): PDF 가 있는 쪽 중 바뀐 것은 1613000 58쪽 78.28→98.48·59쪽 29.72→96.27 뿐(issue1853 25·27쪽, rowbreak-problem-pages 15쪽은 SVG 만 바뀌고 Δ 0.00). PDF 없는 변화는 1977964 1쪽(표 전체 −0.69px, 한/글 2020 MCP 변환본 왼끝 84.67 에 85.50→84.83, 점수 98.54→98.48)과 합성 stored-nested-content-flow/square-*(어울림 첫 표가 칸 가운데 x=128 → 왼쪽 x=48, square-top 한/글 2020 변환본 대비 72.8→77.3 — README 가 overlay 판에서 이미 '우연한 가운데 배치'로 기록한 같은 앵커). 1342000 SVG 동일. 중간 변형: 측정·컷만 고친 상태에서 1341000 29쪽 −23.8·30쪽 −31.3(고아 줄 되감기가 중첩 행을 한 행 일찍 자름 — 막음), 1613000 58쪽 위 여백 이중(+3.5px)·59쪽 뒤 문단 +9px(둘 다 이 커밋에서 고침)
    • 55ddf0690(2dfc0f184 대비, 샘플 1,252 SVG + 1342000): SVG 가 바뀐 쪽은 1613000 85쪽뿐(22.93→98.52). 중간 변형: 같은 증상을 '새 쪽 첫 줄 vpos ≤ 그 문단 위 간격' 으로 쪽 경계 판정(꼬리 흡수)을 넓히면 aaaaaa 8쪽 −17·hwp3-sample16 35쪽 −24·48쪽 −23·issue2004 2쪽 −15 등 20쪽 넘게 떨어져 버렸다
    • 06dc305d5(55ddf0690 대비, 샘플 1,252 SVG + 1342000): PDF 있는 쪽 변화는 1613000 197쪽 98.88→99.83·198쪽 58.82→99.90 뿐. PDF 없는 issue5828/landscape_rowbreak_bleed.hwp(156505020 구역 3 절단 픽스처) 14→15쪽 — 픽스처 자체는 한/글 MCP 변환이 실패해 원본 156505020 을 한/글 2020 MCP 로 변환(43쪽)해 대조: rhwp 41→43쪽, 전쪽 평균 98.17(90% 미만은 43쪽 69.5 하나 — 마지막 표 행 호원대 하나가 42쪽에 남지 않고 43쪽으로 감). 기존 issue_5828_landscape_rowbreak_absorbs_only_one_boundary_row 통과
    • de2315e55(06dc305d5 대비, 샘플 1,252 SVG + 1342000): SVG 가 바뀐 쪽은 80168 hwp 60·61쪽(90.62→92.30, 36.28→96.00)과 80168 hwpx 판 60·61쪽(17.44→18.41, 24.53→24.54 — hwpx 판은 기존 저점)뿐. 중간 변형: 같은 표 89·90쪽 이어받는 행 상자를 '선언 − 앞 조각' 으로 넓히면 18095317 21쪽 −100·nested_table_text_caption 8–12쪽 −57−87·1382000 30·36쪽 −80−86·21761835 5·6쪽 −52·−57 등으로 깨져 버렸다
    • 7be2810a5(a5f9ea1c9 대비, 샘플 1,252 SVG + 1342000): 오른 쪽 54(1613000 139–183쪽 21쪽 → 99.3100, 1341000 27·28쪽, hwpx_sample2 6쪽 +4.2, fragment_ghost 15쪽 +4.8, 1342000 다수), 내린 쪽 9 — 1342000 81쪽 −2.9(기존 86.7, 한/글이 끝 행에 한 줄 더 넣는 기존 컷 차이), fragment_ghost 18쪽 −1.1·1342000 251쪽 −0.7(둘 다 표 아래·끝 행 윗변은 PDF 에 더 가까워짐: 18쪽 윗변 −1.44→−0.10, 251쪽 아래 −2.58→+0.09), 21761835 hwpx 2쪽 −0.7(행 20 상자가 닫는 선보다 2.4px 짧던 기존 차이에 1.33px 더), 그 밖 기존 90% 미만 −0.4−0.6. 중간 변형: 줄인 몫을 행 자신의 다음 부분에도 넘기면 1342000 338–345쪽 −26~−31·21761835 3쪽 −10.5, 개체 든 행에도 적용하면 1341000 29쪽 91.5→86.4 — 막았다
    • 35f46f163(0e93b92a9 대비, 샘플 1,252 SVG + 1342000): 오른 쪽 95(+0.3~+1.8 — table_scattered_header hwp·hwpx 다수, 80168 2·47·60·73·88·122쪽, 86712, 1613000 144–183쪽, 76076 hwpx 판 한/글 2024 PDF 2·18·52·67쪽 +0.6), 내린 쪽 4(1342000 32·227·232·298쪽 −0.3−0.8, 모두 기존 6775%). 중간 변형: 원장도 줄인 띠를 쓰면 21761835 3쪽 −15.8·1342000 80쪽 −24.6·224쪽 −21.7, 내용 컷 행까지 줄이면 1342000 203쪽 −10, 걸침 몫 계산에 줄인 상자를 넘기면 1342000 338–345쪽 −26~−31 — 모두 막았다. PDF 가 없는 문서(task1753, issue3637, issue1891_external_bindata_link, 80550, 156403546, hwpspec)도 같은 1.33px 띠 단축이며 대조하지 않았다. 80168 WASM TSV 는 이전 WASM 으로 찍은 것을 다시 찍었다(같은 head Native 는 6쪽만 바뀜, WASM 57쪽 91.07→89.84 는 빌드 차이)
    • 65e20ecba(1185e8a29 대비, 샘플 1,252 SVG + 1342000): 1613000 195쪽 96.9→99.9, 196쪽 59.3→99.6, 197쪽 61.9→98.9, 198쪽 49.3→58.8, 200쪽 96.6→99.9, 201쪽 54.9→98.4, 202쪽 51.4→99.9, 1342000 335–345쪽 +2~+32(338–345 → 9799.5), 334쪽 −0.31. 그 밖 변화 없음. 중간 변형: 바깥 아래 여백을 빼지 않으면 80168 122·123쪽 −74(행 23 이 남음), 자기 칸 없는 행까지 받으면 1342000 33쪽 −40, 첫 조각까지 넣으면 합성 계약 opening_rowspan_block_cuts_after_the_first_row 실패 — 셋 다 조건으로 막았다. 띠 끝에도 100HU 를 적용하는 변형은 1342000 44·47·225·226쪽 +20+31 이지만 80쪽 −24.6·224쪽 −21.7·21761835 3쪽 −15.8 이라 넣지 않았다. 1342000 WASM TSV 는 이전 WASM 으로 찍은 것을 다시 찍었다(같은 head Native 는 334–345쪽만 바뀜)
    • b4452b801(5cf391db0 대비, 샘플 1,252 SVG + 1342000): 1613000 126쪽 93.2→99.7, 127쪽 91.0→99.6, 128쪽 91.6→99.1, 1480000 43쪽 97.4→99.99, myeonjeok 1쪽 98.64→98.58(표 아래 1081.3px ↔ 한/글 2020 MCP 변환본 ≈1080.5, 종전 1078.3 — 끝 줄간격 접기로 우연히 가깝던 값), hwpspec 42쪽 +0.24(쪽 수 181≠178 기존)·97쪽 ±0, hwp-3.0-HWPML 38쪽 40.0→40.1(MCP 변환본). 하락 쪽 없음. 중간 변형(paint 접기 예외를 컷 일치만으로 판정)은 1613000 139·141·167·180쪽을 −1−4 내려 같은 상자 값 조건으로 좁혔다(그 변형에서 함께 오르던 152–178쪽 +1+3.6 은 이번에 넣지 않음). 1480000 WASM TSV 는 b30e9e020 무렵 WASM 으로 찍은 것을 다시 찍었다 — 같은 head 의 Native 는 43쪽만 바뀌므로 그 밖 쪽의 차이(±0.1~4, 169쪽 90.38→89.67)는 WASM 빌드 차이다
    • dd2e52e71(리베이스 전 200beb58f 대비, 샘플 1,252 SVG + 1342000): SVG 가 바뀐 쪽은 1613000 191–193쪽뿐(Native 77.8/41.3/57.1 → 99.9/99.97/99.85, WASM 77.5/40.7/56.7 → 99.9/99.96/99.9). 1342000 SVG 동일
    • 리베이스(6ed1682c3) 전후: 샘플 SVG 중 바뀐 쪽은 누름틀 양식 5쪽(BlogForm_BookReview·MovieReview·Recipe 1쪽, field-01·field-01-memo 3쪽) — devel cfd06cd2b(누름틀 교체·인쇄 보정) 영향이고 표 쪽은 리베이스 전과 같다
    • 이전 리베이스(8766fb47d) 전후: 샘플 SVG 13,416쪽 전부 바이트 동일(리베이스 전 빌드 ↔ 200beb58f release)
  • 글꼴: RHWP_FONT_PATH = hwp·windows TTF + KoPubWorld TTF/OTF + KoPub2.0 (모두 존재). 21761835 의 한/글 PDF 는 나눔명조가 Haansoft Batang 으로 대체돼 있으나 줄 간격이 저장값(1272HU)과 같아 행 높이 비교에는 영향 없음을 확인.

새 회귀 테스트(tests/cases/ 원본만, generated·manifest 미포함):

테스트 수정 전 수정 후
rowbreak_span_cell_page_end_lines::span_cell_lines_inside_the_closing_line_stay_on_the_page (1342000 199쪽 r62 c8 셋째 줄 = 행 63 첫 줄과 같은 쪽, 행 63 c4 특성 은 다음 쪽 — PDF 와 같음) · ::span_end_row_keeps_its_declared_height (202쪽 행 92 = 선언 97.1px ±1) 실행 FAIL(셋째 줄 200쪽 / 행 92 100.0px) PASS
rowbreak_short_row_whole_carry::crossing_rowspan_owns_the_page_end_band (21761835 2쪽 행 20 띠 · 3쪽 빈 줄+패딩 · 걸침 칸 행 조각 합 = 선언 252px±1.5) 띠 문턱 없는 코드에서 FAIL(행 20 조각 50.99px = 내용) PASS
rowbreak_short_row_whole_carry::crossing_rowspan_without_declared_slack_leaves_the_band_empty (반례: 70833 2쪽 표 끝이 본문 끝보다 30px 넘게 위) 몫 상한 없는 변형에서 FAIL(표 끝 1024.9px) PASS
rowbreak_short_row_whole_carry 앞 7건(1480000 표 15·18, 21761835 4쪽 블록 끝, 1480000 44쪽 저장 컷·빈 줄, 21761835 2쪽 걸침 분배, 1342000 반례) 각 단계 FAIL(커밋 작성 시 확인) PASS
rowbreak_short_row_whole_carry::grown_boundary_row_continues_and_successor_keeps_its_stored_line (1613000 185쪽 26행 분할·187쪽 pi=4 21행 통째 시작·188쪽 pi=7 0행 시작) 수정 전 head 의 dump-pages 로 확인: 185쪽 pi=1 이 통째(Table, 조각 없음)라 첫 단언이 실패하는 상태. 테스트 자체를 수정 전 코드로 실행하지는 않았다 PASS
issue_6950_paragraph_end_topbottom_anchor::first_fragment_uses_paragraph_reference_not_text_or_outer_box 에 문단 윗변 앵커 변형 추가(같은 첫 조각이어야 함) 수정 전 식(앵커 − 위 간격)으로는 위 간격 20·80 에서 기대값과 다르다(계산 확인, 실행 안 함) PASS
rowbreak_short_row_whole_carry::crossing_span_end_row_takes_the_larger_span_share_up_to_the_closing_line (1613000 139쪽 행 49 = 걸침 칸 5128 − 앞 행 2882HU = 29.95px, 144쪽 행 139 = 2882HU, 154쪽 행 51 = 닫는 선 731.91px) 실행 FAIL PASS
rowbreak_short_row_whole_carry::crossing_span_row_closes_at_the_fragment_bottom_line (1613000 196·197·201·202쪽 시작 행 44·71·43·65, 195쪽 행 43 내용이 저장 용지·여백으로 계산한 닫는 선 712.99px 안) 실행 FAIL(196쪽이 43행으로 시작) PASS
rowbreak_short_row_whole_carry::crossing_span_row_beyond_the_closing_line_moves_whole (반례: 80168 123쪽이 행 23 으로 시작) 수정 전 PASS(보호 테스트) — 바깥 여백을 빼지 않은 중간 변형에서 행 23 이 122쪽에 남는 것은 A/B 로만 확인 PASS
rowbreak_short_row_whole_carry::stored_restart_end_row_closes_at_its_declared_or_cut_content_box (1613000 126·127쪽 행 17·28, 1480000 43쪽 행 118, myeonjeok 1쪽 행 29 의 끝 상자 = 저장 메트릭의 max(선언, 컷 내용)) 실행 FAIL(127쪽 행 28 135.99px) PASS
rowbreak_short_row_whole_carry::continued_table_bottom_caption_keeps_the_whole_table_gap (1613000 128쪽 끝 조각 캡션 간격 = 121쪽 통째 표) 실행 FAIL(20.67 vs 11.33px) PASS
rowbreak_short_row_whole_carry::whole_table_on_a_fresh_page_leaves_its_successor_on_the_stored_line (1613000 191쪽 pi=11 첫 조각이 행 4 에서 끝나고 192쪽이 행 5 로 시작 — 한/글 PDF 의 1.2 교육 계획 / 1.2.1) 실행 FAIL(수정만 되돌린 코드: 192쪽이 6행으로 시작) PASS
rowbreak_short_row_whole_carry::continued_row_closes_at_its_next_stored_restart (1613000 표 pi=1133 123쪽 끝 컷 [40,37]·124쪽 [51,70]·이어받기 연속, 123쪽 행 상자 = 저장 (66020+1200+282)HU = 900.03px, PDF 899.96) 실행 FAIL([41, 37]) PASS
rowbreak_short_row_whole_carry::empty_host_terminal_successor_keeps_its_stored_line (1613000 125쪽 pi=1135 첫 줄 = 본문 위 + vpos 15006HU = 275.68px) 실행 FAIL(291.65px) PASS
rowbreak_short_row_whole_carry::nested_table_page_frame_splits_its_single_cell_box (1613000 pi=585 58쪽 끝 컷 [32]·59쪽 연속, 58쪽 「항공기 이륙」까지·59쪽 「상승비행」부터 합계 170 까지, 58쪽 상자 윗변 = 본문 위 + 바깥 위 여백 (5670+283)HU = 79.37px) 실행 FAIL(수정 전: 58쪽에 조각 없음, 통째 표 / 위 여백 수정만 되돌림: 83.12px) PASS
rowbreak_short_row_whole_carry::continuation_successor_keeps_its_stored_line_below_the_box (59쪽 pi=587 첫 줄 = 본문 위 + vpos 20884HU = 354.05px, PDF 글자 윗변 353.84) 실행 FAIL(수정 전 121.44px / 뒤 문단 수정만 되돌림 364.37px) PASS
rowbreak_short_row_whole_carry::square_nested_table_with_zero_offset_keeps_its_left_anchor (58쪽 22×2 표 왼끝 = 칸 왼끝 + 안 여백 510 + 바깥 왼 여백 140 HU = 8.67px, PDF 괘선 92→101px) 실행 FAIL(칸 가운데) PASS
rowbreak_short_row_whole_carry::footnote_margin_does_not_cut_body_beyond_the_footnote_height (1613000 84쪽이 pi=817 을 갖고 85쪽이 pi=818 로 시작, 그 첫 줄 = 본문 위 + vpos 700HU = 84.93px) 실행 FAIL(84쪽 문단 목록에 817 없음) PASS
rowbreak_short_row_whole_carry::stored_fragment_table_does_not_bleed_a_landscape_boundary_row (1613000 구역 3 pi=1 197쪽 끝 행 96 전, 198쪽 행 96 부터 통째) 실행 FAIL(197쪽 끝 97) PASS
rowbreak_short_row_whole_carry::no_line_seg_cell_paragraph_end_is_a_row_split_boundary (80168 hwp 표 pi=516 60쪽 끝 컷 [1,1]·61쪽 연속) 실행 FAIL(60쪽이 행 12 앞에서 끝남) PASS
rowbreak_short_row_whole_carry::stored_restart_cuts_the_last_row_of_a_page (기존, 1613000 204쪽) — PASS (중간 변형 205쪽에서 실패 확인)
split_row_stored_reset_valign::stored_paragraph_reset_fragment_keeps_cell_center_alignment FAIL (0.00px) PASS
split_row_stored_reset_valign::single_cell_stored_reset_fragment_is_aligned_once (1×1 반례) 1×1 제외 없는 코드에서 FAIL (27.88 > 20.72px) PASS
first_frame_remainder_capped_by_row_box, stored_zero_origin_later_page_row_fits, tac_picture_stored_rewind_next_page, rowbreak_rowspan_opening_row_cut, rowbreak_carried_row_band 각 커밋 작성 시 FAIL 확인(앞 작업 세션 기록) PASS (nextest)
issue_7702_condense_word_tail::pre_2020_stored_word_tail_joins_the_condensed_line (1342000 151·154쪽 꼬리가 앞 줄에) 실행 FAIL PASS
issue_7702_condense_word_tail::joined_tail_row_keeps_its_declared_height (151쪽 r=56 칸 ≤ 선언+1px) 실행 FAIL(줄이 안 붙어 대상 줄 없음; 높이 단언 단독은 실험 바이너리로 57.1px 확인) PASS
issue_7702_condense_word_tail 반례 3건(114쪽 앞 경계 유지, 25쪽 condense 없음, 21_언어 1쪽 한/글 2020 저장) PASS PASS
issue_7702_condense_word_tail::stored_row_generation_comes_from_the_container_last_save (메타데이터 판정) 새 필드 — 결함 검출 증거 아님 PASS
devel issue_7692::partial_plain_row_keeps_source_minimum_and_owned_contents·issue_6981::continuation_height_respects_varying_page_budgets 50dcb0078(원장에 inset 을 더한 리베이스 중간 변형)에서 실행 FAIL PASS
issue_7702_humanmyeongjo_ascii_and_condense_end::condensed_paragraph_end_line_breaks_where_hancom_2024_does (합성 fine·coarse 사다리의 d 마다 다. 줄 = 한/글 2024 PDF 의 줄) 실행 FAIL(d=0–6·−20 에서 rhwp 두 줄) PASS
issue_7702_humanmyeongjo_ascii_and_condense_end::humanmyeongjo_ascii_advances_match_hancom_2024_ladders (94자 × 3 조건 장치 전진폭 = 한/글 2024 PDF 가c 주기 − 가) 실행 FAIL(, 59/60 . 59/60 ( 69/70 등) PASS
issue_8101_no_adjust_fragment_bottom::no_adjust_table_fragment_closes_at_the_outer_bottom_margin (1342000 121–125쪽 noAdjust 표 조각 아래 = (53859 − 141) HU = 716.24px) 실행 FAIL(714.92px) PASS
issue_8101_no_adjust_fragment_bottom::spanning_cell_end_row_keeps_its_declared_height_and_page_owns_the_line (126쪽 행 60 = 선언 2982HU, «자전거를 탈 때» 줄 126쪽·127쪽 «현장체험학습») 실행 FAIL(46.29px) PASS
issue_8101_no_adjust_fragment_bottom::ordinary_table_fragment_keeps_the_bottom_inset (반례: 157쪽 noAdjust 아닌 표 = (53859 − 141 − 100) HU) PASS(보호) PASS
issue_8105_fragment_outer_top_and_restart_trim::continued_offset_table_reopens_its_outer_top_margin (1342000 26–29쪽 윗변 = (5669 + 4252 + 141) HU) 실행 FAIL(132.27px) PASS
issue_8105_fragment_outer_top_and_restart_trim::own_before_restart_keeps_the_closing_line_on_the_page (55쪽 행 21 p1 / 56쪽 p2 «제10조(학생예방교육)») 수정 전 PASS(종전 위 여백 누락이 방을 남김) · ① 만 넣고 ② 를 뺀 코드에서 실행 FAIL PASS
issue_8105_fragment_outer_top_and_restart_trim::deferred_first_fragment_spends_its_offset_and_opens_the_outer_top (hwpx_sample2 6쪽 윗변 (2835 + 283) HU, 아래 (84188 − 2835 − 283 − 100) HU) 실행 FAIL(아래 1075.81px) PASS
issue_8105_fragment_outer_top_and_restart_trim::consumed_offset_does_not_reopen_an_already_opened_margin (반례: 156555538 9쪽 윗변 (5670 + 140) HU) PASS(보호) · 그리기 직접 가산 중간 변형에서 79.31px PASS
issue_8105_declared_row_blank_tail::blank_tail_above_the_limit_opens_the_next_page (픽스처 2·6·8·12쪽 첫 칸 = 행 1 빈 띠, 높이 = 선언/75 − 앞 쪽 그린 높이 ±0.5) 실행 FAIL(저장 줄 블록 띠 없음) PASS
issue_8105_declared_row_blank_tail::blank_tail_within_the_limit_is_absorbed_at_the_page_end (4·10쪽은 «다음» 행 2 로 시작) 실행 FAIL(10쪽 15px 띠) PASS
issue_8105_declared_row_blank_tail::stored_rows_carry_declared_and_ending_span_remainders (1342000 59쪽 행 9 띠 = 9366HU − 58쪽 «부산» 칸, 61쪽 첫 칸 = 행 17 빈 띠 = 103310HU − 58–60쪽 병합 칸 조각 합) 실행 FAIL PASS
issue_8105_numbered_stored_word_tail::numbered_cell_paragraph_rejoins_its_stored_word_tail (1342000 250쪽 …갈등 현상 탐색하기 한 줄, 꼬리 기 단독 줄 없음, 행 49 칸 = 3882HU/75 ±0.5px) 실행 FAIL(줄 …탐색하 / 기) PASS
issue_8105_numbered_stored_word_tail::unnumbered_cell_paragraph_keeps_its_stored_word_tail (반례: 59쪽 번호 없는 …2017.11.13., 제 / 정] 두 줄 = 정본) PASS(보호) PASS
issue_7702_condense_word_tail::recomposed_tail_that_does_not_fit_stays_on_the_next_line (종전 stored_tail_without_condense_keeps_the_stored_break — 25쪽 …필 / 요 는 번호 문단이라 다시 나누는 대상이지만 새 줄 나눔에서도 두 줄. 이름·설명만 고치고 단언은 그대로) PASS PASS

정렬 검사의 대조값은 구현 계산을 재인용하지 않고, 같은 문서에서 그 칸만 valign=Top 으로 바꿔 다시 조판한 출력이다.

조판 변경 근거 — 소비 경로

  • 분할 판정: typeset/table/scan/runner/row_step.rs(저장 재시작 컷, 짧은 끝 행 통째 이월, 블록 끝 닫기) → continuation/fragment/emit.rs(조각 확정·[layout/table] 걸침 칸 초과 높이를 행에 나누는 방식이 한/글과 다르다 — 1342000 edu 31쪽 +7.7px·32쪽 −9.4px, 쪽 끝 줄 수가 갈린다 (#7226 잔여) #7531 쪽 끝 띠·원장) → physical_rows.rs(다음 조각 행 계획, 띠 몫 상한 crossing_span_page_end_band) → paint layout/table_partial.rs(end_row_owns_stored_frame 이면 끝 줄간격 접기 생략).

  • 행 높이 풀이: height_measurer.rs::solve_rowspan_row_heights(가장 먼저 끝나는 제약 우선) — 측정·scan·paint 가 같은 row_heights 를 소비.

  • 셀 정렬: table_partial.rs 의 plain_cut_frame_owns_alignment → frame_owns_alignment → effective_align. 새 조건은 기존 row_cut_ends_at_stored_page_reset 판정을 재사용.

  • 자란 경계 행: height_measurer.rs::fit_measured_table_to_declared_height_with_outcome 의 [layout] 비공백 호스트 표의 선언 높이 fit이 원본 행높이를 일괄 축소 — 시장구조조사 표 Ⅵ-5 #7147 예외 뒤 declared_fragment_closes_on_a_grown_row → 측정 row_heights 를 scan·paint 가 함께 소비.

  • 첫 조각 원점: typeset/table/block/prepare.rs(호출자 placement_para_start_height) → float_placement.rs::for_first_fragment → record_paragraph_float_placement 를 paint 가 그대로 소비.

  • 이어받는 행의 저장 재시작 컷: table_layout.rs::row_stored_restart_cut_after(= stored_plain_restart_cut 에 시작 컷·문단 첫 줄 재시작) → row_step.rs 용량 컷 직후 교체(stored_restart_capacity_keep 로 고아 가드 면제, 예산 검사는 그대로) → emit·paint 는 같은 end_cut 소비.

  • 빈 호스트 끝 조각 뒤 문단의 NextLine 계획: emit commit_fragment 가 stored_successor_line_origin 기록 → paint ParagraphFloatPlacement::paragraph_end(호스트 아래 간격 생략)·stored_frame_successor_shared_spacing_px(뒤 문단 위 간격 한 번) — typeset paragraph/flow.rs 도 같은 함수.

  • 끝 조각 뒤 문단: table_layout.rs::text_host_terminal_successor_gap ← 공통 native_text_frame_terminal_successor_gap 를 emit(commit_fragment 흐름 끝·가시 배제 띠 하단)과 paint(layout.rs 의 source_terminal_gap)가 같은 입력으로 호출.

  • 중첩 표 호스트 갭: float_placement.rs::nested_host_gap_start 를 측정 height_measurer.rs::cell_nested_controls_bottom 과 배치 table_layout.rs::calc_nested_controls_bottom_height 가 같은 입력(앞 문단 흐름 표 끝)으로 호출 → 측정 행 높이를 scan·paint 가 소비.

  • 중첩 표 저장 첫 조각 경계: table_layout.rs::stored_object_frame_row_count → cell_units_uncached 의 중첩 행 유닛 hard_break_before(부모 유닛으로 전파) → advance_row_cut_inner 가 그 유닛에서 멈춤(rewind_rowbreak_orphan_before_hard_break 는 중첩 행끼리 되감지 않음) → emit·paint 는 같은 end_cut.

  • 1×1 첫 조각 원점: fragment/budget.rs 의 단일 칸 위 여백 가산(흐름 원점이 이미 연 계획은 건너뜀) → record_paragraph_float_placement → paint.

  • 칸 안 어울림 중첩 표 가로: table_layout.rs 중첩 표 x 의 [renderer] 칸 안 어울림 중첩 표가 저장 horzOffset 을 안 써 왼쪽으로 49.9px 치우친다 (#5702 의 가로 축 잔여, 2025571) #5787 어울림 분기(오프셋 ≥ 0) — export-pdf: '직인' 텍스트박스 위치 이탈 + 페이지 하단 용지규격 문구 소실 #3308 가운데 분기 앞.

  • 각주 쪽 가용 높이: typeset/state/transition.rs::available_height(각주 차감 0·보수 여백 > 0 이면 하한 = 본문 − 각주 높이) → 문단 fit prepare_fit_budget·표 예산이 같은 값을 소비. paint 각주 영역은 page_layout.rs::update_footnote_area(본문 바닥 − 각주 높이)로 같은 경계.

  • 가로 용지 허용치: typeset/table/scan/landscape.rs::storage_records_page_cuts(셀 되감김 또는 저장 첫 조각 프레임) → whole_row_shape·short_row_shape 가 허용치를 끔 → scan 의 일반 용량 컷.

  • 문단 끝 컷 계약: layout/table_paragraph_cut.rs::row_cut_plain_paragraph_contract(문단 끝 컷은 저장 글줄 없이도 통과) → row_step.rs 의 plain_paragraph_keep_contract 가 25px 최소 상단 문턱을 면제 → 같은 end_cut 을 emit·paint 가 소비.

  • 저장 앵커 분할 판정: typeset/table/block/entry.rs saved_anchor_overlaps_current_flow → saved_anchor_splits_here → 선언 이월 생략.

  • 빈 줄: layout/paragraph.rs·flow.rs → empty.rs::hide_rowbreak_guide, height_cursor.rs::vpos_adjust; 셀 끝 vpos 0 재시작 빈 줄의 줄 상자 소유는 table_layout.rs::empty_unit_owns_flow_line_box.

  • (리베이스 후속) HWP5 저장 표 예산: continuation/fragment/budget.rs native_source_frame + 병합 칸 → rowbreak_fragment_frame_bottom 의 inset 생략 → physical_frame_bottom → page_avail → avail_for_rows. 재조판 프레임(같은 파일 reflow 분기)·paint table_partial.rs page_cap 은 devel 대로 inset.

  • (리베이스 후속) 쪽 끝 띠: fragment/emit.rs 원장 띠는 devel 식 (frame_rows + header_overhead − partial_height), 그리는 띠만 SINGLE_CELL_PAGE_FRAGMENT_BOTTOM_INSET_HU − budget.reflow_frame_bottom_inset 를 한 번 뺀다. 방 = split_end_reserved(스캔이 예약한 패딩 포함 컷 상자).

  • (리베이스 후속) 걸침 예약: scan/runner.rs post-loop stored_span_fragment_minimum 의 grow = minimum − consumed 를 끝 행 override 와 consumed 가 같이 소비.

  • ([layout] 한/글 2014 저장 줄 나눔과 한/글 2020 출력이 갈리는 칸 — 공백 폭·줄 끝 넘침 허용 차로 행이 한 줄 높아진다 (1342000 +700px) #7702) 저장 줄 판정: stored_cell_reflow.inc.rs fresh_rows_absorb_stored_tail(프레임 복제에 resolve_stored_line_segs_in_frame(stale=true)) → 같은 Reflowed 경로 → 측정 HeightMeasurer::measure_table_impl·typeset·paint 가 같은 줄 소비. 저장 세대는 DocumentCore 로드 시 SourceProvenance::stored_rows_before_hancom_2020(HWP5 요약 / HWPX version.xml) → StoredGeometryPolicy.

  • ([layout] 한/글 2014 저장 줄 나눔과 한/글 2020 출력이 갈리는 칸 — 공백 폭·줄 끝 넘침 허용 차로 행이 한 줄 높아진다 (1342000 +700px) #7702 189쪽) 휴먼명조 ASCII 폭: font_metrics_overlays.rs HUMANMYEONGJO_LATIN_0 → 측정기 장치 전진폭 → 재조판 줄 나눔·paint 글자 위치가 같은 측정기를 소비. 문단 끝 condense 판정: composer/line_breaking.rs::fill_one_interval 의 w_hwp_fit(끝 글자 자간 트림을 자연폭으로 들어갈 때만 생략) → 같은 줄 나눔 결과를 측정·typeset·paint 가 소비.

  • ([layout] 1342000 90% 미만 136쪽 분류 — 한/글 2014 저장 줄 재조판·번호 머리 영역·쪽 끝 한 줄 연쇄 #8101) 비끝 조각 inset: float_placement::rowbreak_fragment_bottom_inset_hu(table) → single_cell_page_fragment_bottom(예산 budget.rs 재조판 프레임·원본 프레임, paint table_partial.rs page_cap) · emit.rs 그리는 띠(unreserved_page_end_band)·원본 닫힘 판정 · row_step.rs 걸침 칸 닫는 선. 같은 함수 하나라 예산·그리기·원장이 같은 하단을 쓴다.

  • ([layout/table] 1342000 남은 90% 미만 132쪽 — 이어지는 조각 바깥 위 여백(세로 오프셋 표)·자기 앞 간격 되감김의 끝 줄간격 #8105) 이어지는 조각 위 여백: float_placement::native_multirow_rowbreak_reopens_outer_top 을 예산(budget.rs)·그리기(table_partial.rs)가 함께 소비. 뒤 줄간격: table_layout.rs::stored_page_reset_cut_trailing_trim ← advance_row_cut_inner 용량 컷 → 같은 end_cut·조각 높이를 emit·paint 가 소비. 오프셋 소진: float_placement::para_offset_consumed_by_page_break(para, table, …) 를 예산·whole_fit·typeset·controls/order·table_partial 여섯 곳이 같은 입력으로 호출, 소진 시 예산 host_before 와 그리기 바깥 위 여백 OR 묶음이 같은 원점.

남은 차이 (해결하지 않음)

  1. 21761835 3쪽 24행은 44.9px 로 한/글 43px 보다 1.9px 크다(걸침 칸이 덮는 행 조각 합은 선언 252.0px 와 같다 — 행별 래스터 오차 범위로 본다).

  2. 90% 미만 쪽(이 PR 이전부터): 표 분할 경로 — 70833 5–7쪽, 80168 90쪽(이어받는 행 상자 −8px)·93쪽(제목 문단 쪽 귀속), 1480000 11·41·145·155쪽, 1342000 다수. 문단·그림·캡션 경로 — 1480000 14·80–82·130·141쪽(그림 캡션이 앞 쪽에 남음), 70833 18쪽.

  3. 1613000 구역 1 끝 행 중 155·162쪽 +7.0, 166쪽 +5.6, 182쪽 −4.2px 는 남았다(162·166쪽은 rhwp 의 행 측정 높이가 한/글보다 큰 별도 차이). 21761835 2쪽 행 20 상자는 닫는 선보다 3.7px 짧다.

  4. 1613000 58쪽 상자 아래 선은 rhwp 992px·PDF 999px(한/글은 첫 조각을 선언 높이 920.5px 프레임으로 닫는다), 59쪽 이어진 조각 아래 선은 −5px(캡션도 5px 위). 두 쪽 모두 95.9% 이상.

  5. 80168 의 90% 미만은 리베이스 뒤 7쪽(37·90·93·109·111·133·139, Native)이다 — 리베이스 전 18쪽 중 20·21·76·77·143 등 2×2 조문 대비표 쪽은 그사이 devel 변경으로 90% 이상이 됐다. 남은 쪽은 모두 devel 과 같은 값이며 이 PR 에서 고치지 않는다. 아래 표는 리베이스 전 18쪽의 원인 분류를 그대로 둔다.

    쪽 원인 상태
    20·21·76·77·109·143 2×2 조문 대비표가 한 줄 일찍 갈림(한/글은 쪽 끝 마지막 줄의 뒤 줄간격 14.9px 를 세지 않고 받는다). 그 셀은 저장 글줄이 없고 옆 칸은 빈 줄 저장 글줄 있는 유닛에 끝 줄간격 트림 시도 → 75544 hwpx 32쪽 +43.5, 1342000 63쪽 −14.6 혼재로 되돌림
    133·134 표 분할 아님 — 저장 글줄 없는 셀 재조판에서 굵은 맑은 고딕 숫자 폭(rhwp Bold 0.58em, 한/글 Regular 0.55em)으로 줄이 하나 늘어 쪽 컷이 밀림 굵은 맑은 고딕 전진폭 — 한/글은 Regular 폭으로 조판하는 것으로 보임 (80168 133·134쪽 줄바꿈 한 글자 차) #8079
    90 이어받는 행 상자 −8px(PDF 31+31 = 선언 62.4) 일반 폴백 시도 시 18095317·21761835·1382000 등 −50~−100 → 폐기
    93 제목 문단 쪽 귀속(문단 흐름) 표 밖
    37·111 1×1 표 묶음(표 분할 아님) 미분석
    17·43·73·120·125·139 85~89.5 경계 쪽 미분석

미검증

  • grown_boundary_row_continues_and_successor_keeps_its_stored_line 와 issue_6950 추가 단언의 수정 전 FAIL 은 실행하지 않고 덤프·계산으로 확인했다(위 표).

  • hwpspec 표 40 반례는 회귀 테스트로 넣지 않았다: hwpspec 은 최저 29.8% 로 [대표 이슈] 문서 전체 피델리티 개선과 회귀 검사 재구축 #7445 보류 목록에 있고 회귀 추가의 90% 선행 조건에 못 미친다. 근거는 A/B(현 head 에서 표 40 배치가 b30e9e020 와 같음)와 pdf/hwpspec-2024.pdf 35쪽(쪽 번호 25) 대조 — 표 40 이 쪽 맨 위에 통째로 있다.

  • issue1880 4쪽 −0.58(99.2→98.6): 4쪽 빈 문단·pi=6 호스트 줄이 저장 vpos(PDF 와 같은 140.0px)로 올라가고 pi=6 표 윗변이 PDF 173.5 에 대해 174.2(종전 174.2)로 같다. −0.58 을 만든 영역은 따로 판독하지 않았다.

  • 1342000 쪽 경계(행 92·쪽 수)를 직접 잡는 회귀 테스트는 넣지 않았다: 관련 200쪽이 89.7% 라 회귀 추가의 90% 선행 조건에 못 미친다. 근거는 위 전쪽 TSV(415쪽 = PDF)와 A/B.

  • crossing_rowspan_owns_the_page_end_band 의 수정 전 FAIL 은 빈 줄 소유 변경만 들어간 중간 상태에서 확인했다.

  • 1341000 표 113 반례(중첩 행 고아 되감기)는 회귀 테스트로 넣지 않았다: 관련 28쪽 87.1%·31쪽 66.6% 로 90% 선행 조건에 못 미친다. 근거는 A/B(최종 head 의 28–31쪽 컷이 8c847d933 와 같음)다.

  • 156505020 원본(저장소 밖 실문서 코퍼스)·1977964·square-top 의 기준 PDF 도 한/글 2020 MCP 변환본(scratch)이다.

  • task2070·3112461·156403546 의 기준 PDF 는 한/글 2020 MCP 변환본(scratch, 저장소에 넣지 않음)이다.

  • f296dbc21 의 휴먼명조 표는 ASCII(U+0020–007E)만 바꿨다. Latin-1 등 다른 범위, 장평 ≠ 100% 조합은 한/글 사다리로 재지 않았다.

  • 위 8개 외 문서의 전쪽 TSV(샘플 1,248 SVG A/B 로 바뀐 쪽만 PDF 대조).

🤖 Generated with Claude Code

@planet6897
planet6897 force-pushed the fix/devel-table-scan-regression branch from 0a88147 to dd54037 Compare October 17, 2026 12:00
@planet6897 planet6897 changed the title fix(조판): RowBreak 표 분할·이어받기를 저장 쪽 경계 기록대로 — 1480000·21761835·1613000·17253153 (부분 개선) fix(조판): RowBreak 표 분할·이어받기를 저장 쪽 경계 기록대로 — 1342000 쪽 수 415 일치·21761835·1480000·1613000 (부분 개선) Oct 17, 2026
@jangster77
jangster77 self-requested a review October 17, 2026 15:04
@jangster77 jangster77 added this to the v1.0.0 milestone Oct 17, 2026
@jangster77 jangster77 added bug Something isn't working layout 문서 레이아웃/페이지네이션: 표·그림 배치, float/anchor, 줄·행 높이, 겹침·클리핑 rendering SVG/Canvas/PDF 등 렌더 출력과 시각 표시: 그리기, 표시 누락, bbox, paint 정합성 table table rendering and edit labels Oct 17, 2026
@planet6897
planet6897 force-pushed the fix/devel-table-scan-regression branch 2 times, most recently from 4c83c61 to 06ae02f Compare October 17, 2026 21:23
@planet6897

Copy link
Copy Markdown
Contributor Author

이 PR 의 01e0a2459(1342000 31쪽)가 #7531 의 31쪽 증상(「경북」 행 28.6px → 정본 20.8)도 해소합니다 — head 06ae02fd2 에서 표 윗변 기준 행 경계가 정본과 ±0.3px, 쪽수 415. 합성 통제 실험으로 걸침 칸 배분 규칙 자체는 한/글과 같음을 확인했고(#7531 코멘트), 32쪽 「제주」 행 −5.7px 잔여는 #7743 에 적었습니다. 병합되면 #7531 을 닫겠습니다.

planet6897 and others added 13 commits October 19, 2026 17:00
PR edwardkim#7882(5601665·e5812d9fa)는 원본 셀 문단의 인접한 두 저장 줄이 모두
`vertical_pos == 0` 인 재시작을 저장 물리 경계로 인증해, 그 행을 전체 행 수용 경로에서
뺐다(`SourceFrameQuery` 의 `declared_source_frame`). 인증은 둘이다.
- 행이 선언 첫 개체 프레임(`common.height`)을 가로지른다(또는 같은 행 동료가 확인) —
  선언 기하의 근거라 저장 쪽 나눔과 무관하다.
- 첫 프레임 뒤 행이고 원본 행 상자 합이 첫 프레임을 넘는다 — 저장 당시 그 행 안에 쪽
  나눔이 있었다는 기록일 뿐이다.

둘째 근거를 첫째와 같이 취급해, 지금 흐름에서 쪽 위·중간에 놓인 행도 그 재시작에서 끊었다.
1342000_edu_curriculum_map.hwp 구역 12 표 행 132(「삶의 목적은 무엇인가? (삶의 목적)」
저장 2줄 vpos 0/0)를 쪽 위 120px 에서 끊어 213px 만 쓴 쪽이 생기는 등 문서가 418 → 422쪽이
됐다(한/글 2022 PDF 415쪽, 그 행을 끊지 않는다).

인증 종류를 `SavedZeroOriginWitness::{OpeningFrame, LaterPage}` 로 가르고, `LaterPage` 는
행 전체가 남은 예산에 들어가지 않을 때만 원본 물리 경계로 쓴다. 쪽 끝에 걸린 행은 종전대로
재시작에서 자른다 — 의도한 원 사례 table_scattered_header_rowbreak(hwp·hwpx) 47쪽 row99
「6가 크로 / 뮴)」은 수정 뒤에도 p47 rows 59..100 endCut [1], 52쪽이다.

측정(devel 463c48c 기준, compat 2022): 1342000 422 → 419쪽(edwardkim#7882 이전 2231761 418).
남은 +1(375쪽)은 구역 26 표가 edwardkim#7882 의 이어받기 바깥 위·아래 여백 예약(1.9px×2)과 상류 낡은
저장 셀 줄로 쪽마다 1행씩 덜 담는 별개 축이다.

시험: stored_zero_origin_later_page_row_fits (합성 입력 계약, HWPX 저장 후 재로드)
- later_page_zero_origin_restart_does_not_cut_a_row_that_fits: 수정 전 FAIL(두 줄이 1·2쪽으로
  갈림), 수정 후 PASS.
- later_page_zero_origin_restart_still_cuts_a_row_at_the_page_end(대조군): 수정 전후 PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`stored_first_frame_row_remainder`(108edfb, edwardkim#7882)는 원본 첫 개체 프레임에서 끊긴 행의
남은 물리 높이를 `측정 행 높이 − 첫 프레임 몫` 으로 내서 다음 조각 시작 행에 넘긴다. 측정
행 높이가 선언 상자보다 큰 행에서는 그 초과분이 내용(마지막 줄의 줄간격 포함)이 만든 높이라
빈 물리 띠가 아니다. 그 초과분까지 넘겨 이어받기 상자가 남은 내용보다 길어졌다.

80168_regulatory_analysis.hwp 5쪽: 2행 표 행 1(선언 869px·측정 929.6px)의 이어받기가 33.6px
(남은 내용 22.4px)로 잡혀, 한/글 2024 PDF 가 마지막 글줄 바로 아래에서 닫는 상자를 11px
더 내렸다. 물리 잔여의 기준을 `min(선언 행 상자, 측정 행 높이)` 로 둔다. 선언 상자가 내용보다
큰 행의 빈 띠를 넘기는 edwardkim#6803 의 의도는 그대로다(선언 상자가 없으면 종전 측정값).

측정(svg rasterizer, compat 2024): 80168 hwp 5쪽 83.55 → 100.00, 4·6쪽 99.60·99.91 무변화.

시험: first_frame_remainder_capped_by_row_box — 이어받기 칸 바닥과 마지막 글줄 바닥 사이 빈
띠가 아래 안 여백 + 줄간격 절반 이하인지(관계). 수정 전 FAIL(13.05px), 수정 후 PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… WASM overlay)

- 80168 hwp 5쪽(2024 PDF): Native 99.61 / WASM 100.00
- issue1853 hwpx 16쪽(2020 PDF): Native 99.60 / WASM 99.57
- 1342000 PDF 233 = rhwp 236(2022 PDF, 쪽 내용으로 정렬): Native 69.77 / WASM 70.78 —
  행 132 가 이제 끊기지 않지만, 이 base(devel)는 상류 쪽에서 4행가량 앞서 시작해 90% 미만이다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
atomic TAC top-fit(edwardkim#409)은 분할할 수 없는 인라인 그림이 본문 하단을 60px 안에서
넘쳐도 현재 쪽에 남긴다. 그 그림 문단의 저장 줄이 되감기고 통째로 안 들어가면
(edwardkim#5755 의 stored_vpos_rewind_overflow_break) 한/글은 그 문단을 다음 쪽 첫머리에
둔 것이므로 스필 예외를 걸지 않는다. 분할 진입(split_entry::should_advance)은 이미
같은 값을 보고 있었고, 넘침 허용 경로만 그 값을 받지 않았다.

1480000-201900698 pi=88(그림 6, 370px): 19쪽 984.7px 로 본문 948.7px 를 넘기던
배치가 한/글 2020 PDF 처럼 20쪽 첫머리로 간다. 이후 21쪽의 그림 7 수용도 사라지고
전체 쪽수가 205(PDF 205)가 된다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
edwardkim#1145 는 작은 rowspan 묶음을 행 중간에서 자르지 않는다. 쪽 끝에 묶음의 무엇도
온전히 놓이지 않을 때는 맞지만(edwardkim#1145 표본: 잔여 15.2px < 0행 17.3px), 0행이 잔여에
들고 0행에서 시작하는 rowspan 칸의 내용도 0행 안에 다 들면 0행 뒤의 컷은 어떤 칸의
글자도 자르지 않는다. 한/글 2020 PDF 는 1480000-201900698 표 9·17 의 0행만 앞 쪽
끝에 둔다(표의 저장 높이 3526 HU 도 0행과 같다). rhwp 는 표를 통째로 넘겨 36~40·
50~52쪽이 두 행씩 밀렸다.

판정은 이월 게이트(prepare)가 한 번 하고 BlockTableContinuationPreparedState 로
행 스캔에 넘긴다. 스캔은 첫 조각의 0행 묶음에만 그 결과를 소비한다. 다음은 기존대로
묶음을 통째로 둔다: 묶음 전체가 잔여에 드는 경우(task1725 pi=631), rowspan 칸 내용이
0행을 넘는 경우(task1753 pi=51), 0행이 제목 행인 경우(1613000 pi=1143).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
저장 첫 조각 프레임이 행 안에서 끝나고 그 행 내용이 프레임에 다 들면, 종전에는 행을
프레임 안에서 닫아(complete_last_row) 선언 높이의 남은 빈 띠를 버렸다. 되감긴 후속
문단의 저장 원점이 «남은 띠 + 뒤 행들 + 표 바깥 위·아래 여백»과 같으면 한/글은 그
띠를 다음 쪽 첫머리로 넘긴 것이다. 그때는 행을 닫지 않고, 행 스캔이 그 행에서 추정
문턱(MIN_TOP_KEEP_PX) 대신 저장 컷을 따른다 — 내용은 이 조각, 띠는 다음 조각.

띠로 시작하는 끝 조각은 아래 바깥여백 예약 경로가 start_cut 비어 있음을 요구해
빠졌고, 조판 흐름만 여백을 더해 그리기가 후속 문단을 그만큼 위에 두었다. 시작 행의
남은 높이를 넘겨받은 띠로 세어 같은 저장 줄 인증으로 여백을 예약한다.

1480000-201900698 표 14(pi=275): 46쪽 첫머리 띠 23.04px, 후속 문단 저장 위치 일치.
46쪽 61.2 → 100.0, 47쪽 61.8 → 98.2 (Native). A/B 변화 2문서(1490000-200800034 는
표 안 띠만, 뒤 흐름 불변·기준 PDF 없음).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 문단 안 글줄 컷의 25px 최소 상단 면제를 위 행에서 내려온 걸침 칸이 행 윗변을
  가로지르는 경우로 좁힌다(1342000 120·127행은 유지, 1480000 표 15·18 75·117행은 통째 이월).
- 저장 셀 되감김(쪽 컷 기록)이 없는 표에서는 1줄 행의 빈 꼬리만 다음 쪽으로 넘기지 않는다
  (1480000 표 15 110행·표 18 76행).
- edwardkim#2236 걸침 칸 띠 컷에서 저장 내용이 남은 띠에 다 들고 행을 지나 이어지는 걸침 칸이
  없으면 행을 이 쪽 끝에서 닫는다(21761835 56행, 5쪽은 57행부터).
- 회귀: tests/cases/rowbreak_short_row_whole_carry.rs (수정 전 3건 FAIL → 후 4건 PASS)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
한/글 2020 PDF 실측(선언 − 남은 띠): 21761835 56행 4.8px·1342000 115행 1.1px·56행 9.9px 는
쪽 끝에서 닫히고, 1342000 43행 15.5px 는 다음 쪽 첫머리에 빈 띠를 남긴다.
기존 TERMINAL_ROW_BOTTOM_SQUEEZE_TOLERANCE_PX(13px, 1741000 실측)를 같은 경계로 쓴다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
행 전체가 들어가도 그 행 뒤에 최소 상단 높이가 남지 않고, 셀 저장 줄이 한 셀의 뒷줄을
vpos 0 에서 다시 시작하면 한컴이 기록한 쪽 컷으로 보고 그 줄에서 자른다. 행이 쪽 중간에
오면 따르지 않는다. 1480000 43쪽 118행·1613000 126·127쪽 17·28행이 한/글 2020 PDF 와 같아진다.
회귀: rowbreak_short_row_whole_carry::stored_restart_cuts_the_last_row_of_a_page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- edwardkim#1686 안내 줄 흡수는 되감긴 다음 앵커의 저장 위치가 현재 흐름 위치에서 빈 줄들의 저장
  전진을 모두 담을 만큼 아래면 흡수하지 않는다(1480000 44쪽 pi=264: 677.8 + 26.4 = 704.2px,
  pr-1674 는 앵커가 흐름보다 위라 계속 흡수).
- 앞 빈 문단의 저장 vpos 가 단 높이 밖(앞 쪽 좌표계)이면 되감긴 현재 문단의 기준을 그 값에서
  역산하지 않고 순차 흐름을 따른다(pi=265 에 trailing 11.7px 를 한 번 더 주지 않는다).
1480000 44쪽 50.9 → 98.5%(Native).
회귀: rowbreak_short_row_whole_carry::page_44_keeps_the_empty_line_after_the_stored_row_cut

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- solve_rowspan_row_heights: 미지 행 하나인 제약을 풀 때 그 행을 걸친 더 일찍 끝나는 제약이
  아직 풀리지 않았으면 기다린다(진전이 없을 때만 종전처럼 하나를 푼다). 21761835 행 11~17 칸이
  미지 행 11 을 136px 로 채워 행 10~11 블록(105.9px)을 139.7px 로 깨던 문제.
- stored_fragment_row_plan: 1행 칸이 없는 행도 그 행에서 끝나는 걸침 칸의 남은 요구로 정하고,
  루프가 방금 다시 푼 앞 행도 변경으로 본다. 1쪽에서 449.1px 를 쓴 칸 (6,0)의 남은 13.6px 를
  2쪽 행 10 이, 행 11~17 칸의 남는 높이를 행 17 이 받는다(한/글 2020 PDF 와 1px 이내).
21761835 2쪽 50.1 → 94.4%, 1342000 33쪽 59.5 → 100%(31쪽은 분할 행 세로 정렬 차이로 96.6 → 88.8).
회귀: rowbreak_short_row_whole_carry::rowspan_extra_goes_to_the_last_row_across_the_page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
planet6897 and others added 10 commits October 19, 2026 17:03
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…0 85쪽

1613000 84쪽 각주 한 줄(31.4px)은 꼬리말 밴드(37.8px)에 다 들어가 각주 차감은 0 인데, 보수 여백
3000HU(40px)가 따로 붙어 본문 끝이 931.4px 였다. 빈 문단 `pi=817` 의 저장 줄(936px)은 paint 가
여는 각주 구분선(본문 위 950.4px, 한/글 2020 PDF 와 같음)보다 위인데도 85쪽으로 밀려 쪽 전체가
37px 내려갔다. 이 경우 가용 높이의 하한을 '본문 − 각주 높이'로 둔다(그 밖의 각주 예약은 그대로).

샘플 1,252 SVG + 1342000 A/B: 바뀐 쪽은 1613000 85쪽뿐(22.9→98.5).
(같은 증상을 '새 쪽 첫 줄 vpos ≤ 위 간격'으로 고치는 변형은 aaaaaa·hwp3-sample16·issue2004 등
20쪽 넘게 −1~−24 로 떨어져 버렸다.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
표 개체 높이가 행 상자 합보다 작게 저장된 원본(`native_stored_table_has_fragment_frames`)은 한/글이
그 표를 쪽에서 갈랐다는 저장 사실이다. 셀 사다리 되감김이 있는 표와 같이 edwardkim#1672 가로 허용치
(경계 행을 본문 아래로 흘려 받음)를 끈다.

- 1613000 부록 105×3 표: 197쪽이 빈 구분 행 96(20.9px)을 본문 아래(659.1/642.6px)로 받아 198쪽이
  한 행 늦었다. 198쪽 58.8→99.9, 197쪽 98.9→99.8.
- 156505020(issue5828 픽스처 원본, 한/글 2020 MCP 변환본 43쪽): rhwp 41→43쪽 = 변환본, 전쪽 평균
  98.2(43쪽 69.5 — 마지막 표 한 행 차이 남음). 픽스처 14→15쪽, 기존 edwardkim#5828 검사 통과.
- 샘플 1,252 SVG + 1342000 A/B: 그 밖 변화 없음.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
문단 유지 계약(`row_cut_plain_paragraph_contract`)은 저장 글줄이 없는 문단을 통째로 제외해,
위 행에서 내려온 걸침 칸이 가로지르는 행에서도 25px 최소 상단 문턱이 첫 문단 컷을 버렸다.
문단 끝 컷은 글줄 분할 없이 문단 경계를 그대로 쓰므로 저장 글줄이 없어도 유효하다. 문단 안
컷만 종전대로 저장 글줄을 요구한다.

80168 hwp 표 `pi=516` 행 12: 60쪽이 첫 문단에서 닫히고 61쪽이 「하는 규제」로 열린다(한/글 2024 PDF).
61쪽 36.3→96.0, 60쪽 90.6→92.3. 샘플 1,252 SVG + 1342000 A/B: 그 밖 PDF 있는 쪽 변화 없음
(80168 hwpx 판 60쪽 +0.97, 61쪽 ±0.01 — 기존 저점).
(같은 표 89·90쪽 이어받는 행 상자를 '선언 − 앞 조각' 으로 넓히는 변형은 18095317·nested_table_text_caption·
21761835 등 −50~−100 으로 깨져 버렸다.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devel 위로 리베이스하며 드러난 두 어긋남.

- 스캔은 내용 컷 행을 컷 경로에 따라 내용 전진량(`split_end_limit`)·패딩 포함 컷 상자·물리 띠
  가운데 하나로 예약한다. emit 의 걸침 띠는 방을 `split_end_limit` 에서 재서, 패딩 포함 상자를
  예약한 경로에서 닫는 선보다 패딩만큼 짧았다(21761835 2쪽 행 20: 전진량 47.25 · 예약 50.99px,
  조각 아래 1040.5 ↔ 한/글 2020 PDF 1044). 스캔이 행마다 실제로 예약한 증분을
  `BlockTableRowScan::split_end_reserved` 로 넘기고 emit 이 그 값에서 잰다.
- devel 26877ee 이후 재조판 프레임 하단(`rowbreak_fragment_frame_bottom`)은 걸침 칸이 있는 표에도
  비끝 조각 inset(100HU)을 뺀다. 원장 띠가 그 프레임에서 재면 inset 을 한 번 더 빼서 그리는 띠가
  1.33px 짧았다(1613000 154쪽 행 51: 730.57 ↔ 닫는 선 731.91). 예산이 프레임이 실제로 뺀 inset 을
  함께 넘기고, 원장 띠는 그 inset 앞의 물리 띠로 잰다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
리베이스(50dcb00) 뒤 남은 어긋남 셋.

- devel 26877ee 가 `rowbreak_fragment_frame_bottom` 에서 걸침 칸 예외를 없애 HWP5 저장 표의
  원본 프레임 예산에도 비끝 조각 inset(100HU)이 들어갔다. 한/글 2020·2022·2024 PDF 1342000
  149쪽은 행 36·37 의 병합 칸이 걸친 행 40 첫 줄(19.76px)을 그 쪽에 두고 아래 괘선을 716.0px
  (본문 − 바깥 아래 여백)에 긋는다. inset 을 빼면 방이 19.25px 라 뒤 쪽이 모두 밀렸다. 병합 칸이
  있는 HWP5 저장 표의 예산만 inset 없이 잰다. 재조판 일반 행 프레임(edwardkim#7642 edwardkim#7028)과 paint 상한,
  통째로 받은 끝 행의 닫는 선은 그대로 둔다. 149쪽 괘선 715.43 ↔ PDF 716.0, 149–151쪽 행 경계 PDF 일치.
- 50dcb00 이 원장 띠를 inset 앞 물리 띠로 늘려, 다음 조각이 그린 상자보다 1.33px 많이 소비한
  것으로 셌다(issue_7692 partial_plain_row 112.4/113.75, issue_6981 FAIL). 원장 띠는 devel 처럼
  프레임에서 잰 값 그대로 두고, 그리는 띠에서 프레임이 이미 뺀 inset 을 다시 빼지 않는다(1613000
  154쪽 유지).
- `stored_span_fragment_minimum` 의 끝 행 확장은 저장 행 높이 합(`physical`) 기준으로 상자를 키우면서
  예약은 `minimum` 까지만 올렸다. 스캔이 수용한 행 합이 저장 합보다 크면 그린 조각이 예약보다
  커져 본문을 넘었다(issue_6981 합성 예산 변형 42..62행: 4.64px, 아래 695.56 > 본문 694.13). 상자는
  예약이 실제로 늘어난 만큼만 키운다.

남은 실패: rows_inside_a_crossing_rowspan_still_split_after_one_line(1342000 165·166쪽 고정). 저장
LineSeg 가 두 줄로 나눈 셀 문단을 한/글 2020 인쇄는 한 줄로 맞춘다(151쪽 행 56, 160쪽 행 67).
devel 은 저장 줄을 따르므로 행이 커져 그 뒤 쪽 경계가 어긋난다. 이번 변경 범위 밖.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
한/글 2014 로 저장한 1342000 의 칸 문단은 공백 최소값(condense) 흡수 없이 낱말 끝 글자만
다음 줄로 보낸 저장 줄을 가진다. 한/글 2020 인쇄는 그 꼬리를 앞 줄에 붙인다(151쪽
`…시연하|기`, 154쪽 `…찬반 토|론`).

- 저장 제품이 한/글 2020(11.x) 이전이고, 양쪽 정렬+condense 문단의 마지막 저장 줄이 앞 줄
  낱말의 나머지뿐이면 같은 프레임으로 새로 끊어 보고 줄 수가 줄 때만 저장 줄을 버린다.
  판정과 실제 줄이 같은 프레임 결과다.
- 저장 제품은 컨테이너가 기록한 마지막 저장에서 읽는다(HWPX 가 원본 HWP5 요약을 실어도
  version.xml 을 따른다).
- 측정기의 edwardkim#6135 저장 extent 증인이 재조판된 문단에도 원래 저장 사다리를 써 행이 옛 줄 수
  높이로 남던 것을 고친다.

1342000 416→415쪽(=한/글 2020 PDF), 성취기준 코드 쪽 일치 21.2%→97.8%.
samples 1252건 SVG 변화 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… TSV (code head 065125a)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
대표 27쪽 Native/fresh WASM review·overlay 와 9개 문서 전쪽 TSV(브랜치 Native·WASM, devel efc52af Native)를
새 head 에서 다시 찍었다. 파일 이름은 CONTRIBUTING 의 <입력>-p<쪽>-<native|wasm>-<review|overlay>.png.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@planet6897
planet6897 force-pushed the fix/devel-table-scan-regression branch from 21ab962 to 8e18113 Compare October 19, 2026 20:31
planet6897 and others added 4 commits October 20, 2026 07:22
끝 행이 물리 상자(end_row_height_override)로 닫히는 조각에서 걸침 칸의 끝 유닛을 끝 행의
내용 컷(그 행 칸의 저장 재시작)까지로만 재던 것을, 그린 상자 높이까지 넓힌다. 다음 조각은
carry 의 끝 유닛에서 잇는다.

1342000 199쪽 r=62 c8(행 62–63) 셋째 줄이 한/글 2020 PDF 처럼 199쪽에 남는다. 200쪽 첫 행이
2.9px 높던 것이 사라져 행 75 가 쪽 끝에서 줄지 않고, 행 57–92 걸침 원장이 부족분을 행 92 에
더하지 않아 202쪽 행 92 가 선언 97.1px(PDF 97.25)로 돌아온다.
Native: 1342000 200쪽 92.8→100.0, 202쪽 92.3→97.3, 203쪽 91.8→99.9, 84쪽 30.4→50.8.
샘플 1,252건 SVG 변화는 1613000 139·140쪽(99.2→99.3, 99.6→99.9)뿐.
회귀: rowbreak_span_cell_page_end_lines (수정 전 2건 FAIL)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…쪽 추가)

Native/fresh WASM(bbdf0abc…) 대표 쪽 review·overlay, 9문서 전쪽 TSV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wardkim#7702)

1342000 189쪽 칸 문단 `…실천한` / `다.` 를 rhwp 재조판이 한 줄로 붙이던 결함.
한/글 2024 에 같은 문단을 폭만 1 HU 씩 바꿔 조판시킨 합성 입력에서 한/글은
26712 HU 부터 붙이고, 수정 전 rhwp 는 약 26668 HU 부터 붙였다.

- 휴먼명조 LATIN_0 를 HMKMM.TTF hmtx × 2 로 교체. 한/글 2024 `가c` 사다리
  94자 × 3 조건이 94/94 일치(종전 edwardkim#2430 래더 표는 37·58·70자 불일치,
  `,` `.` `(` `)` 가 10pt 에서 한 장치 단위 좁음).
- 문단 끝 edwardkim#2470 예외(끝 글자 자간 유지)는 자연폭으로 들어가는 줄에만 쓴다.
  공백 condense 로만 들어가는 줄은 양쪽 정렬 끝 글자를 자간 없는 폭으로 잰다(edwardkim#5678).

검증: 새 회귀 2건 수정 전 FAIL / 후 PASS, nextest 11064/0, lint·tiers OK.
Visual Sweep(Native/fresh WASM): 1342000 189쪽 66.6→98.0, issue5169 4쪽 97.2→100,
합성 입력 최저 99.3, 그 밖 9문서 1074쪽 변화 없음. 36382669 5·6·7쪽 줄바꿈이
한/글 2024 PDF 와 같아짐.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…169 4쪽·휴먼명조 합성 입력 추가)

Native/fresh WASM(1dbb1aab…) 대표 쪽 review·overlay, 9문서 + 36382669·issue5169·합성 5종 전쪽 TSV.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
planet6897 and others added 2 commits October 20, 2026 16:35
한/글 2020 Print 1342000 의 쪽 끝 표 아래 괘선(쪽 척도를 걷은 값)은 noAdjust(표 속성 bit 3)
표가 본문 아래 − 바깥 아래 여백에 −0.03~−0.15px(121·170·99·49쪽), noAdjust 아닌 표가 그 선
− 100HU(edwardkim#7095 inset)에 ±0.12px(157·213·108쪽)로 맞는다.

rhwp 는 모든 RowBreak 비끝 조각을 100HU 위에서 닫아, noAdjust 표에서는 조각마다 걸침 칸 몫을
덜 소비했다. 구역 5 표의 걸침 칸 «생활안전»(1–60행) 남는 몫 490HU 가 끝 행 60 에 몰려 126쪽
행이 4.9pt 커졌고, 쪽 끝 줄이 밀려 127–129쪽이 한 줄씩 어긋났다.

inset 을 표마다 정하는 `rowbreak_fragment_bottom_inset_hu` 로 모으고, 예산·그리기 띠·원장·
걸침 칸 닫는 선(row_step)이 같은 값을 쓴다.

검증: 새 회귀 3건(수정 전 2건 FAIL — 121쪽 714.92 ↔ 716.24, 126쪽 행 60 46.29 ↔ 선언 39.76 /
반례 157쪽 inset 유지 PASS), nextest 11067/0, lint·tiers OK, fresh WASM 055828a5….
1342000 126·127·128·129쪽 86.4/76.9/76.9/77.4 → 99.4/99.4/94.8/96.8, 90% 미만 136 → 132,
하락은 기존 저점 5쪽 ≤0.8. 샘플 SVG 변화 17문서 63쪽, PDF 대조 하락 최대 −0.5(sample1-repro 39쪽),
쪽 수 변화 0. PR 9문서·합성 입력 Native/WASM 변화는 1342000 뿐.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Native/fresh WASM(055828a5…) 대표 쪽 review·overlay, 1342000 전쪽 TSV(다른 문서 TSV 는 바이트 동일).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
planet6897 and others added 6 commits October 20, 2026 19:16
- 이어지는 조각의 바깥 위 여백 재개방(`native_multirow_rowbreak_reopens_outer_top`)에서
  `vertical_offset == 0` 조건을 없앤다. 문단 기준 오프셋은 첫 조각에서 소진된다. 한/글 2020
  1342000 구역 1 표(오프셋 5280·752HU) 이어지는 조각 윗변 26–29·31·34·55쪽 = 본문 위 + 141HU.
- 다음 문단이 자기 앞 간격 원점(vpos = 앞 간격)으로 되감기는 저장 경계에서 앞 줄의 뒤
  줄간격을 조각 높이에서 뺀다(`stored_page_reset_cut_trailing_trim`). 1342000 55쪽 행 21:
  p1 vpos 1800 → p2 vpos 500. 한/글 2020 은 p0·p1 을 55쪽에 담는다.
- edwardkim#6143 «문단 오프셋 소진» 판정의 25px 최소 조각을 나눌 수 없는 0행 높이로 넓히고(함수가
  표를 받는다), 소진된 첫 조각은 그 쪽에서 바깥 위 여백을 연다(그리기의 바깥 위 여백 OR 묶음).
  한/글 2024 hwpx_sample2 6쪽: 앵커 1016.48 + 오프셋 4.0 뒤 26.4px < 0행 28.41px → 6쪽 윗변
  = 본문 위 + 283HU, 첫 조각 1037.9px = 저장 첫 프레임 1038.01px. 종전 예산은 오프셋과
  여백을 둘 다 빼 4px 일찍 닫고, 그 몫을 7쪽 조각이 받았다.

검증: 새 회귀 4건(A·C 수정 전 FAIL, B 는 B 만 뺀 코드에서 FAIL, 156555538 반례 보호 PASS),
nextest 11071/0, lint·tiers OK, fresh WASM 0b588054…. 1342000 90% 미만 132 → 126(하락 0).
샘플 SVG 변화 10문서 14쪽: hwpx_sample2 hwp 6·7쪽 98.7/96.7 → 99.8/99.7, hwpx 6쪽 74.9 → 99.8,
75544 31·32쪽 86.7/53.3 → 99.9/97.3, 1480000 41쪽 71.1 → 100.0, 59043 24쪽 −0.1.
issue2439(rhwp 11쪽 / 한/글 2024 10쪽, 기존 불일치) 3쪽 54.9 → 90% 이상, 4쪽 47.9 → 33.1 —
3·4쪽 경계는 한/글과 같아졌고 4쪽은 끝 조각 뒤 간격(+13px, 이 변경 밖의 기존 오차)이 드러남.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…x_sample2 6·7쪽 추가)

Native/fresh WASM(0b588054…) 대표 쪽 review·overlay, 1342000·1480000 전쪽 TSV(다른 문서 TSV 바이트 동일).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
한/글 2024 합성 사다리(probes/make_declared_row_band.py)로 측정한 규칙:
내용이 이 쪽에서 끝난 분할 행은 닫는 선까지 그리고, 남은 선언이 1282HU(17.09px)를
넘으면 다음 쪽 첫머리 빈 띠로 넘기며 그 이하는 흡수한다(병합 칸은 원장으로 이어받음).
칸 여백·표 기본 여백·글자 크기·저장 줄·병합 칸 유무와 무관(17.0 흡수 / 17.2 이월).

- 흡수 상한을 칸 마지막 줄 높이에서 위 상수로 바꾼다(재조판·저장 경로 공통).
- 완료 행 + 걸침 칸에서도 상한을 넘는 남은 선언은 띠로 넘긴다(edwardkim#7642 의 일괄 제외 대체).
- 저장 줄 행의 칸 내부 분할 예산은 본문 아래까지라 끝 행 상자가 그리기 닫는 선보다
  383HU 컸다. 내용 완료 끝 행은 재조판 프레임(닫는 선)까지로 줄이고, 그 선언 상자는
  끝 줄간격으로 접지 않는다. 병합 칸 원장·남은 선언이 같은 상자를 소비한다.
- 그 행에서 끝나는 저장 줄 병합 칸의 남은 선언도 완료 행에서 띠가 된다
  (1342000 61쪽 51.6px = 행 8–17 병합 칸 잔여).

1342000(한/글 2020): 90% 미만 126→123쪽, 59·61·62·307쪽 44–73→99.8–100.
하락 250·251·352쪽은 같은 쪽 중간의 기존 행 높이 차(69.1↔51.9, 머리 행 45.2↔18.0)의 연쇄.
픽스처 declared_row_band.hwpx 12쪽 Native/fresh WASM 최저 100.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…7쪽, edwardkim#8105 빈 띠 픽스처 추가)

Native(native-skia)·fresh WASM(96095cdf…) 대표 쪽 review·overlay, 1342000·1480000·21761835 전쪽 TSV 갱신,
declared_row_band 픽스처 TSV 추가. 다른 대표 PNG·TSV 는 바이트 동일.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1342000 250쪽 행 49 칸 문단 `…갈등 현상 탐색하` / `기`(한/글 2014 저장 줄)를 한/글
2020·2022·2024 Print 는 모두 한 줄로 다시 나눈다. rhwp 는 저장 줄을 따라 행이 69.1px
(정본·선언 51.9px)였고 그 17.2px 가 250·251쪽 뒤 행을 밀었다.

edwardkim#7702 의 «저장 줄 꼬리를 프레임의 새 줄 나눔이 앞 줄로 흡수하면 다시 나눈다» 는
condense 문단만 대상이었다. 한/글 2024 합성(probes/make_numbered_stale_tail.py)에서
문단 머리(«-»·«1.» 번호)를 그리는 문단은 폭이 맞는 저장 줄도 쓰지 않고 다시 나누고,
번호 없는 문단은 폭이 맞으면 저장 줄을 따른다(줄 flags·저장 제품 버전 무관). 1342000
정본도 번호 문단 꼬리 39건을 붙이고 번호 없는 `…제|정]`·`…일|부개정]` 은 두 줄로 둔다.
→ 대상을 condense 또는 문단 머리가 있는 문단으로 넓힌다. 실제로 붙는지는 종전대로 새
줄 나눔이 정한다(25쪽 `…필|요` 는 새 줄 나눔에서도 두 줄 = 정본).

1342000(Native·fresh WASM): 90% 미만 123→97, 250쪽 78.6→99.6·251쪽 69.8→98.0, 357–371·
282–288쪽 등 32쪽 상승. 하락 5쪽 — 175쪽 −1.6(한/글이 꼬리를 못 넣는 경계 근접 문단), 272–274·
359쪽 −3~−4(행 높이는 정본과 같아졌고 쪽 끝 분할 한 줄 차이의 기존 연쇄가 남음).
샘플 전수: 규칙이 발화하는 문서는 1342000·interview.hwp 뿐, interview 출력은 바이트 동일.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
대표 쪽 전체를 code head 9f2b241 의 Native(native-skia)·fresh WASM(sha256 c4ed9986…)으로
다시 찍었다. 바뀐 PNG 는 없고 1342000 250·251쪽 review·overlay 를 더했다. 전쪽 TSV 는
1342000 만 바뀜(Native·WASM 90% 미만 123→97, 바뀐 쪽 37). pr_review_gate 전부 passed, 최저 94.57.

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

This branch has not been deployed

No deployments
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