Task #470 + #471 + #473: cross-column vpos-reset/박스 stroke_sig + 그림 crop scale 정정#472
Task #470 + #471 + #473: cross-column vpos-reset/박스 stroke_sig + 그림 crop scale 정정#472planet6897 wants to merge 67 commits into
Conversation
exam_kor.hwp 24페이지 → 20페이지 정합 작업 1단계. - 페이지별 단별 used/hwp_used/diff CSV (output/debug/task435/) - 회귀 대상 5문서 페이지 수 (exam_kor 24, exam_eng 8, k-water-rfp 28, hwpspec 177, synam-001 35) - RHWP_TYPESET_DRIFT 출력 캡처 (pi=0.30, pi=1.25 split 진단) - compute_body_wide_top_reserve_for_para 산정 경로 추적 핵심 진단: col 1 reserve 306.1px (HWP 실제 94.5px 대비 +211.6px 과대). 원인: Paper-rel 좌표를 body-rel 변환 없이 그대로 reserve 에 누적. Stage 2 에서 typeset.rs:2127-2172 의 VertRelTo::Paper 분기 정정. 수행계획서/구현계획서/Stage 1 보고서 포함.
compute_body_wide_top_reserve_for_para 의 VertRelTo::Paper 분기에서 body-rel 변환 누락 정정. body 와 일부만 겹치는 (header→body 침범) 케이스에서 Paper-rel 좌표를 그대로 reserve 에 누적하던 버그 수정. 수정 전 reserve = shape_y_offset(paper) + h + outer_bottom = 306.1 px 수정 후 reserve = max(0, shape_top_abs - body_top) ... = 94.4 px 결과: - exam_kor.hwp: 24 → 22 페이지 (page 2, 15 orphan 해소) - pi=0.30, pi=1.25 split → FullParagraph - 회귀: exam_eng 8, k-water-rfp 28, hwpspec 177, synam-001 35 유지 - cargo test: 1062 passed Stage 3 에서 일반 페이지 누적 -100~-300px 정정 (22 → 20).
원래 가설 ("표/도형 후 컬럼 잔여 공간 산정 부족") 재검토.
RHWP_TYPESET_DRIFT 분석 결과 diff 메트릭은 typeset cur_h 누적
(height_for_fit, trail_ls 제외) vs hwp_used (last line vpos+lh)
의 좌표계 차이를 측정하는 것일 뿐, "rhwp 가 채울 수 있는데 못 채운
잔여 공간" 이 아님을 확인.
실제 22→20 페이지 단축 장애물:
1. 섹션 1 페이지 14: Square wrap 표 + col 0 over-fill (1225>1211)
→ col 1 under-use (64px)
2. 섹션 1 페이지 15: 단일 컬럼 출력 (단정의는 2단인데 단 1 누락)
3. 섹션 2 페이지 18: pi=11 split + pi=13 [단나누기] orphan-like
3가지 전부 해결 시 22→19 가능 (목표 20 도달).
옵션 A/B/C 결정 필요 (현 상태 종료 / Stage 4 확장 / Stage 4 부분).
옵션 A 종료: 24→22 페이지 (Stage 2 col 1 reserve 정정). 잔여 22→20 미달성, 3가지 별도 메커니즘 (Square wrap over-fill, 단일 컬럼 출력 버그, col 0 cur_h over-advance) 별도 task 분리 권고. edwardkim#393 (옵션 A) 본 task Stage 2 로 적용 완료, close 가능.
수행계획서(task_m100_439.md) + 단계1 진단 보고서. 핵심 발견: - 이슈 가설의 engine.rs:702-711 는 fallback 경로 (RHWP_USE_PAGINATOR=1). 기본 활성 엔진은 typeset.rs::TypesetEngine. - 실제 버그 위치: typeset.rs::place_table_with_text (1400-1467). engine.rs 의 !is_wrap_around_table 가드 (engine.rs:1349, 1422) 누락. - 페이지 14 col 0 used=1225.8 (본문 1211.3 초과 +14.5) 정확히 재현. 코드 변경 없음 — 임시 디버그 코드는 모두 revert.
place_table_with_text 의 정확한 cur_h 누적 추적 (디버그 후 revert): - Square wrap 4 표가 pre_height + table_total 합산 → +244.88 px 과다 - HWP 의도: max(호스트 텍스트, 표 + v_offset) 만 누적 수정안: typeset.rs::place_table_with_text 에서 current_height += max(pre_height, v_off + table_total) (Square wrap 시) 코드 변경 없음 — 임시 디버그 println 모두 revert.
typeset.rs::place_table_with_text 에서 Square wrap (어울림) 표일 때 current_height 누적을 pre_height + table_total → max(pre_height, v_off + table_total) 로 변경. 호스트 문단 텍스트와 어울림 표는 같은 수직 영역을 공유하므로 더 큰 쪽만 한 번 누적해야 HWP layout 의도와 일치. PageItem 자체는 PartialParagraph + Table 모두 push (layout 렌더링 보존). 검증: - 페이지 14 col 0 used 1225.8 → 1036.1 px (≤ 1211.3 충족) - exam_kor.hwp 22 → 20 페이지 (목표 ≤ 21 충족) - 회귀 샘플 6 종 (exam_eng/math, 21언어, aift, 2010-01-06, biz_plan) 페이지 수 동일 - cargo test 1066 개 모두 통과 - SVG 렌더링 정상 closes edwardkim#439
Stage 4 회귀 검증 결과: - 149 개 sample HWP 전수 페이지 수 비교: exam_kor 만 22→20 변경, 148개 동일 - cargo test 1066 passed - DoD 전부 충족 본 task 완료. closes edwardkim#439.
typeset.rs::place_table_with_text 의 Square wrap 표 누적 정책을 pre_height + table_total → max(pre_height, v_off + table_total) 로 변경. 효과: - exam_kor.hwp 페이지 14 col 0 used 1225.8 → 1036.1 px (over-fill 해소) - exam_kor.hwp 22 → 20 페이지 - 149 개 sample 중 exam_kor 만 변화, 148 개 동일 (회귀 0건) - cargo test 1066 passed closes edwardkim#439
…문제 수정 - 수행/구현 계획서 + Stage 1·2 보고서 작성 - src/renderer/layout.rs: paragraph border merge 그룹을 col_area 바닥/꼭대기로 클램프 - exam_kor p2/5/8/15 의 세로 구분선이 PDF 와 일치하는 길이로 정상화 (p8: 1671 → 1425, 246px 단축, 페이지 바깥 침범 해소) - vpos-reset 미존중으로 인한 텍스트 자체의 overflow 는 별도 이슈로 분리 - snapshot 갱신: tests/golden_svg/issue-267/ktx-toc-page.svg (invisible 구조 rect 의 height 5.34px 변화, 가시 변화 없음)
페이지 번호 박스가 column divider line 과 붙어 보이는 문제 해결. 원인: 꼬리말 paragraph 의 vert=Para + wrap=TopAndBottom 표가 paragraph top 에 배치되어 본문 바닥과 같은 y 에 위치. HWP 의 실제 동작은 첫 라인의 line_height/2 만큼 아래에 anchor 되어 본문과 시각적 갭 형성. 수정: layout_header_footer_paragraphs 에서 해당 조건의 첫 paragraph 표는 y_offset 에 line_height/2 (px) 를 더하여 배치. 검증 (exam_kor.hwp 20p): - 박스 top y: 1422.93 → 1439.47 (PDF 380.6mm 와 일치) - column line - 박스 갭: 0px → 16.3-17.0px (PDF 16.0px 와 일치) - column line 길이/위치는 PDF 자연 그대로 유지 (p1 1131px, p2+ 1226px) - cargo test --release: 1117 passed, 0 failed
이슈 edwardkim#445 의 두 시각적 결함 (paragraph border 페이지 바깥 침범 + 페이지 번호 박스가 column line 에 붙음) 모두 PDF 와 일치하도록 수정 완료. 승인 후 local/devel 머지 + edwardkim#445 close 예정.
- 수행계획서 (mydocs/plans/task_m100_452.md): 옵션 A 선언, 4단계 분해 - 구현 계획서 (mydocs/plans/task_m100_452_impl.md): paragraph_layout.rs:2511-2520 is_para_last_line 분기 제거, is_cell_last_line 만 보존 - Stage 1 보고서 (mydocs/working/task_m100_452_stage1.md): - exam_kor pi=1.line9↔pi=2.line0 step = 15.34px (버그) ↔ 단락내 24.51px - 10종 샘플 페이지 수 baseline 캡처 (/tmp/task_452_baseline/) - 21_언어 p1 col 1 pi=26+보기①②③ fit 확인 (edwardkim#332 회귀 baseline) - orders 갱신: 버그 섹션 edwardkim#452 항목 추가
… + golden 갱신 - src/renderer/layout/paragraph_layout.rs:2511-2519: is_para_last_line 분기 제거. is_cell_last_line(셀 내) 만 trailing 제외 보존, 본문 단락은 모든 줄에서 y += lh + ls 통일. pagination/engine.rs 의 current_height 누적과 정합. - 검증: exam_kor 1페이지 pi=1.line9↔pi=2.line0 step = 15.34 → 24.50 px (단락내 step 과 동일). cargo test --lib 1066 passed. - golden SVG 2건 baseline 갱신 (Task edwardkim#332 에서 갱신된 것을 본 정합으로 재갱신): - tests/golden_svg/issue-147/aift-page3.svg - tests/golden_svg/issue-157/page-1.svg - LAYOUT_OVERFLOW 메시지: 페이지 마지막 단락의 trailing ls (~10.9 px) 가 col_bottom 을 살짝 넘으나 빈 공간이므로 시각 무영향. pagination engine 의 effective_trailing 처리로 페이지 분배는 유지.
paragraph_layout.rs:2511-2520 의 is_para_last_line 분기 제거. 본문 단락 모든 줄에서 y += lh + ls 통일 → pagination/engine.rs 의 current_height 누적과 정합. is_cell_last_line(셀 내) 만 trailing 제외 보존. 효과: exam_kor pi=1.line9↔pi=2.line0 step 15.34→24.50 px (단락내 step 과 동일, PDF 정합). 10종 샘플 페이지 수 변동 0. Task edwardkim#332 회귀 0 (21_언어 p1 col 1 pi=26+보기①②③ fit 유지). cargo test --lib 1066 passed + svg_snapshot 6/6 (issue-147/157 baseline 재갱신). closes edwardkim#452
paragraph_layout 의 skip_text_for_inline_shape 분기 제거. 인라인 글상자가 있는 줄에서 외부 문단 본문이 통째로 스킵되던 버그를 수정. 원인: skip_text_for_inline_shape 가 글상자 내부 텍스트와 외부 문단 본문 텍스트를 혼동하여, 외부 본문(글상자 좌·우의 일반 텍스트)도 함께 스킵하고 있었음. 글상자 자체와 내부 텍스트는 shape_layout 의 inline_shape_position 경로로 별도 렌더되므로 외부 본문을 항상 렌더해도 중복되지 않는다. 검증: samples/exam_kor.hwp 페이지 2 좌측 단 line 2 의 본문 39자(척사파의 ... 거스를) 가 글상자 좌·우로 분리 렌더되어 복원됨. 페이지 수 20 유지, 전체 테스트 1117 passed.
Stage 3 회귀 검증 결과 (1117 tests passed, 페이지 수 회귀 0). Stage 4 최종 결과보고서 및 PR 메시지(`mydocs/report/task_m100_455_pr.md`) 작성. 오늘할일에 Task edwardkim#455 항목 추가.
`on_first_multicolumn_page` 가드는 새 페이지 시작 시 false 로 리셋되어 다단 구역이 여러 페이지에 걸칠 때 후속 페이지에서 `detect_column_breaks_in_paragraph` 호출이 차단됨. HWP 원본의 LINE_SEG vpos 리셋 위치가 무시되어 좌측 단 하단이 col_bottom 을 초과해 그려지던 버그. 수정: `typeset.rs:856` (기본 경로) + `pagination/engine.rs:607` (RHWP_USE_PAGINATOR=1 fallback) 의 가드에서 `on_first_multicolumn_page` 조건 제거. 검증: - exam_kor p2 pi=39 0..4/4..7 → 0..2/2..7 (HWP 원본 정합) - exam_kor LAYOUT_OVERFLOW 36 → 16 (페이지 5/8 의 동일 메커니즘 자동 해소) - 다단 샘플 4종 (exam_eng/math/science/social) 페이지 수 + SVG byte 동일 - cargo test --release 1120 passed, 0 failed closes edwardkim#459
Task edwardkim#463 Stage 2 의 cell_ctx.is_none() 게이팅으로 셀 paragraph 의 invisible border rect 가 본문 큐에서 제거됨. 4개 snapshot golden 이 이전 구조 (셀 paragraph 포함) 로 작성되어 있어 mismatch 발생. 시각 비교 결과 4건 모두 PNG 동일 (table-text 만 1px 폭 anti-aliasing 4/255 차이) 이라 golden 갱신이 적절. - form-002/page-0.svg - issue-157/page-1.svg - issue-267/ktx-toc-page.svg - table-text/page-0.svg
- para_border_ranges 튜플에 para_index 추가 (9 → 10 필드) - build_single_column merge 그룹의 첫/마지막 paragraph index 추적 - sequential 인접 paragraph bf_id 검사로 partial_start/partial_end 보정 - 그룹 첫 paragraph 의 prev paragraph 가 같은 bf_id 면 partial_start - 그룹 마지막 paragraph 의 next paragraph 가 같은 bf_id 면 partial_end - 결과: cross-column / cross-page 박스 연속 시 inner 경계 stroke 미렌더 검증: - exam_kor.hwp 6p 좌측 단 [18~21] 박스 하단 stroke 미렌더 (PDF 일치) - exam_kor.hwp 6p 우측 단 박스 상하단 모두 미렌더 (양방향 연속) - exam_kor.hwp 7p 좌측 단 박스 상단 미렌더 (페이지 경계 연속) - exam_kor.hwp 14p 단일 박스 정상 닫힘 유지 (Task edwardkim#463 회귀 0) - cargo test 1069 + svg_snapshot 6 통과 - 5종 샘플 회귀 0
- mydocs/report/task_m100_468_report.md 작성 - mydocs/orders/20260430.md 신설 (edwardkim#468 완료, edwardkim#464/edwardkim#465/edwardkim#466/edwardkim#467 대기)
…ot 경계 침범 수정 closes edwardkim#469 src/renderer/layout.rs paragraph border 그룹 렌더링에서 partial_start/ partial_end 박스가 col_top 위(헤더선) 또는 col_bot 아래(꼬리말선) 까지 침범하던 현상을 차단. 원인: L1740 `rect_y = y_start - top_pad` 가 cross-column 으로 이어진 partial 박스의 후속 부분에도 적용되어, y_start 가 col_top 으로 클램프된 이후 top_pad (border_spacing.top) 만큼 다시 위로 확장. exam_kor p2 우측 단 (나) 박스 좌·우 세로선이 헤더 가로선(y=196.55) 과 맞닿음. 수정: `effective_top_pad`/`effective_bot_pad` 도입. - is_partial_start → effective_top_pad = 0 - is_partial_end → effective_bot_pad = 0 이전/다음 컬럼에서 이미 inset 처리된 후속 부분은 col_top/col_bot 경계 안쪽에서만 그려지도록 한다. 검증: - 신규 통합 테스트 test_469_partial_start_box_does_not_cross_col_top - exam_kor p2 우측 단 (나) 박스 세로선 y1: 196.55 → 211.65 ✓ - 좌측 단 (가) 박스 영향 없음 (y1 = 242.41 유지) - cargo test 1121 + svg_snapshot 6 모두 통과
closes edwardkim#470 Task edwardkim#321 cross-paragraph vpos-reset 가드가 `cv == 0` (정확히 0) 만 인정해 컬럼 헤더 오프셋 (cv=9014 등) 으로 시작하는 다단의 새 컬럼 reset 을 놓침. 21_언어_기출_편집가능본 1p 의 pi=10 ("적합성 검증이란…") 이 col 0 에 강제 삽입되어 56.2px overflow 발생. 수정: typeset.rs:415, 439 에 다단/단일 단 분기. - 다단(col_count > 1): cv < pv && pv > 5000 (Task edwardkim#470, 컬럼 헤더 오프셋 인정) - 단일 단: cv == 0 && pv > 5000 (Task edwardkim#321 보수적 기준 유지, hwpspec partial-table split 회귀 차단 / issue_418) 검증: - 신규 통합 테스트 test_470_cross_paragraph_vpos_reset_with_column_header_offset - 다단 샘플 OVERFLOW 11건 추가 해소 21_언어_기출 13→10, exam_science 5→0, exam_social 4→1 - hwpspec(단일 단) OVERFLOW 45→45, issue_418 PASS (회귀 0) - cargo test 1122 / 1122 PASS
…로 변경 closes edwardkim#471 Task edwardkim#468 cross-column 박스 인접 검출이 bf_id 동등 비교로 동작했으나, 머지(Task edwardkim#321 v6)는 stroke_sig 기준이라 bf_id 가 다르더라도 visual 동일 하면 한 그룹이 됨. 머지 후 그룹의 g.0 은 첫 range bf_id 만 보존. 본 회귀: 21_언어_기출 1p 좌측 단 (가) 박스가 pi=6(bf=7) + pi=7~9(bf=4) 머지로 g.0=7. composed[10].bf=4. bf_id 비교로 4 != 7 → partial_end 미설정 → 4면 stroke 단일 Rectangle 로 그려져 하단 가로선 발생 (Task edwardkim#470 적용 후 pi=10 이 col 1 로 이동하면서 노출). 수정: layout.rs:1670-1699 의 cross-column 검출을 stroke_sig 비교로 변경. 머지와 동일한 비교 기준 사용으로 일관성 확보. 검증: - 신규 통합 테스트 test_471_cross_column_box_no_bottom_line_in_col0 - cargo test 1123 / 1123 PASS - 21_언어_기출/exam_kor/exam_eng/hwpspec OVERFLOW 회귀 0
devel 의 PR edwardkim#461 (Task edwardkim#459+edwardkim#462+edwardkim#463+edwardkim#468+edwardkim#469) 통합본과 local/devel 의 Task edwardkim#469+edwardkim#470+edwardkim#471 작업 충돌 해결. 해결 내용: - src/renderer/layout.rs: ours (Task edwardkim#471 stroke_sig 비교 채택). devel 의 bf_id 비교는 Task edwardkim#471 에서 정정한 결함이므로 ours 가 superset. - src/renderer/layout/integration_tests.rs: ours (Task edwardkim#469/edwardkim#470/edwardkim#471 통합 테스트 3건 모두 보존). devel 은 edwardkim#469 테스트만 포함. - mydocs/orders/20260430.md: 양측 섹션 병합 (M100 박스 정합 + 잔존 이슈 + PR 처리 PR edwardkim#450). 검증: - cargo test 1072 + svg_snapshot 6 + issue_418 1 + 기타 PASS, FAIL 0.
closes edwardkim#473 `compute_image_crop_src` 가 `original_size_hu` (= ShapeComponentAttr. original_width/height, 표시 HU) 를 crop 좌표 변환 scale 기준으로 사용. HWP crop 은 실제로 이미지 native 픽셀을 96-DPI HU 관행 (75 HU/px) 으로 인코딩 하므로, 사용자가 그림 크기를 변경한 케이스에서 scale 어긋남 발생. 본 회귀: 21_언어_기출 12p `<보기>` 표 내부 그림이 orig=12 HU/px (vs 75) 로 viewBox=13875 산출 → image=2220 px 가 viewBox 의 16% 만 차지 (6.25× 축소). 수정: svg.rs:2385-2404 의 scale 산출을 96-DPI 관행 기반으로 변경. - original_size_hu/img_px 가 75 ± 5% 안일 때만 orig 사용 (역호환). - 아니면 75 HU/px fallback. 기존 unit test 갱신: offset_top_left, fallback_when_original_size_missing 의 가상 입력 (10 HU/px 등) 은 96-DPI 관행 외라 새 정책에 따라 75 fallback 적용. exam_kor_header / no_crop_full_image (75 HU/px) 는 영향 없음. 검증: - 신규 통합 테스트 test_473_picture_crop_viewbox_matches_image_px - 광범위 샘플 7종 / 415 페이지 / 32 nested SVG / 0 viewBox 과대 회귀 - exam_kor partial crop 20건 (헤더 로고) 정상 보존 - 21_언어_기출 12p 그림 정상 렌더 (plain `<image 355×265>`) - cargo test 1078 / 1078 PASS
Task #473 추가 (closes #473)그림 crop 변환의 scale 기준 오류
원인
수정96-DPI 관행 (75 HU/px) fallback. 검증
학습: 1차 회귀 검사 시 |
paragraph가 페이지에 걸쳐 분할(PartialParagraph)될 때 인라인 treat_as_char Shape의 PageItem::Shape가 무조건 마지막 페이지에 등록되어 박스가 잘못된 페이지의 fallback 위치(예: y=742.45)에 출현하던 문제 해결. 근본 원인: TypesetEngine/Paginator의 process_controls가 Shape 분기에서 무조건 st.current_items.push 함. paginate_text_lines가 paragraph를 이미 다음 페이지로 진행시킨 상태이므로 박스가 line 0의 페이지가 아닌 마지막 페이지에 라우팅됨. 그 결과 박스의 페이지 tree에 inline_pos가 없어 shape_layout의 compute_object_position fallback이 잘못된 위치에 박스를 그림. 수정: - pagination.rs에 find_inline_control_target_page 공용 함수 추가: 박스의 char 위치 → line index → 그 line이 라우팅된 (page_idx, col_idx) 반환 - TypesetEngine(메인) / Paginator(fallback) 양쪽의 Shape 분기에서 호출하여 treat_as_char Shape를 박스가 속한 페이지/단의 column_contents.items에 push - shape_layout.rs:218에 회귀 안전장치(D): treat_as_char + inline_pos=None 시 박스 렌더 스킵. RHWP_DEBUG_LAYOUT=1 시 stderr 로깅 - paragraph_layout.rs:2087 빈 paragraph 분기에 Shape의 inline_pos 등록 추가 (Picture만 처리하던 누락분 보강 — D 차단 false positive 방지) 검증: - cargo test --release: 1078 + 모든 통합 테스트 통과 - golden SVG 6건 모두 통과 - samples/21_언어_기출_편집가능본.hwp 페이지 11/12 시각 비교 정상 closes edwardkim#476
…m#476) paragraph 페이지 분할 시 인라인 treat_as_char Shape의 PageItem::Shape가 무조건 마지막 페이지에 등록되어 박스가 잘못된 페이지의 fallback 위치에 출현하던 문제 해결. closes edwardkim#476
페이지 14 [A] 박스(wrap=Square 표)가 단 1 본문이 아닌 단 0과 단 1 사이의 갭 영역에 그려지던 문제 해결. 근본 원인: layout.rs:2256-2270 Square wrap 분기가 col_area.x 만 사용 하고 paragraph effective_margin(=margin_left + indent)을 미반영. TAC 표 분기는 동일 패턴에서 effective_margin 을 적용했으나 Square wrap 분기는 누락. 수정: area_x = col_area.x + effective_margin / area_w = col_area.width - effective_margin - margin_right 로 paragraph 영역 기준 정렬. halign=Right/Center 도 동일 기준 적용 (Task edwardkim#295 호환). 검증: - 페이지 14 [A] 박스: x 580.9 → 605.5 (paragraph 영역 안) - cargo test --release: 1078 + 모든 통합 통과 - 골든 SVG 6건 통과 - Task edwardkim#295 (halign=Right) 동작 호환 closes edwardkim#480
|
처리 결과: cherry-pick 머지 (commit PR 의 67 commits 중 본질 신규 3 Task 분석 후 옵션 A 선택 — Task #470 + #471 cherry-pick, Task #473 제외.
Task #473 제외 사유: 본 작업 사이클의 Task #477 (commit
작업지시자 통찰: "이건 휴리스틱이 아닙니다. 룰입니다." — HWP 표준 명세 룰 (1 inch = 7200 HU = 96 px = 75 HU/px) 단일 적용. Task #473 의 정정 의도는 본 #477 로 이미 해결됨. 위키 페이지: HWP 그림 Crop Scale 룰 — 두 케이스 (PNG = crop 후 / PNG = 원본) 모두 75 HU/px 룰로 자동 정합 처리. 회귀 origin (PR #434 / Task #430) 사례 + 컨트리뷰터 점검 항목 정리. 검증:
@planet6897 Task #470 / #471 정정 감사합니다. 21_언어_기출_편집가능본 OVERFLOW 13→10 + exam_science 5→0 + exam_social 4→1 같은 광범위 정정 효과 확인되었습니다. Task #473 도 의도는 정합했으나 본 작업 사이클에서 같은 결함을 단일 룰 방식으로 먼저 정정한 상태였습니다. |
…스 stroke_sig (cherry-pick @planet6897, Task #473 제외 — 본 #477 룰 충돌)
본 사이클 누적 정정 (5): - Task #474: RowBreak 표 보호 블록 정책 비적용 (k-water-rfp 5쪽) - Task #477: 표 셀 안 그림 클램프 + 이미지 Crop Scale 룰 정합화 (PR #434/Task #430 회귀) - Task #470 + #471: cross-column vpos-reset / 박스 stroke_sig (PR #472 cherry-pick) - Task #431: 분할 표 셀 내 문단 미출력 (단위 mismatch) + dump-pages 진단 도구 - Task #429: 표 셀 배경 image fill 미구현 (BorderFill image_fill 렌더링) 본 사이클 close 이슈 (10): - 정정 완료: #474 / #477 / #431 / #429 - 자동 해결 / 정합 점검: #426 / #407 / #231 / #345 - 구현 중지: #497 / #242 (클라우드 HWP 인라인 — 본 사이클 외) 마일스톤 v2.0.0 이관 (2): #272 (HwpCtrl Action) / #307 (이미지 드래그 앤 드롭) 샘플 추가: - samples/exam_eng-2010.pdf, exam_eng-2020.pdf (이슈 #345 정답지) - samples/hwpx/issue_241.hwpx + pdf (이슈 #241 본질 분석용) 검증: - cargo test --lib: 1080 passed - svg_snapshot: 6/6, issue_418: 1/1, clippy: 0건 - WASM 4,204,760 bytes - 작업지시자 시각 판정 통과 (Task #474 / #477 / #431 / #429)
본 사이클 14번째 PR. 67 commits 중 본질 신규 3 Task. 작업지시자 옵션 A 선택 — Task edwardkim#470 + edwardkim#471 cherry-pick, Task edwardkim#473 제외 (본 작업 사이클 Task edwardkim#477 (75 HU/px 단일 룰) 와 동일 영역 정정). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Task #468 (cross-column 박스 연속 partial 플래그) 후속 정정 두 건. 두 task 는 서로 종속(#471 은 #470 적용 후 노출된 회귀를 정정).
Task #470 — 다단 cross-paragraph vpos-reset 검출 완화
`samples/21_언어_기출_편집가능본.hwp` 페이지 1 좌측 단 하단에 pi=10 ("적합성 검증이란…") 의 처음 2줄이 강제 배치되어 56.2 px overflow. HWP 인코딩상 pi=10 전체가 우측 단 시작 (first vpos=9014, pi=9 last vpos=90426).
원인
Task #321 cross-paragraph vpos-reset 가드가 `cv == 0` 만 인정 → 컬럼 헤더 오프셋 (cv=9014) 인 다단 케이스 미감지.
수정 (`src/renderer/typeset.rs:415, 439`)
다단 / 단일 단 분기:
결과
Task #471 — cross-column 박스 stroke_sig 비교
Task #470 적용 후 21_언어_기출 1p 좌측 단 (가) 박스 하단에 가로선이 그려지는 부작용 발견 (PDF 는 cross-column 으로 우측 단 이어짐).
원인
`src/renderer/layout.rs` paragraph border 머지 (Task #321 v6) 는 stroke_sig (line_type/width/color) 기준이지만, Task #468 cross-column 검출은 bf_id 동등 비교 → 머지 후 그룹의 `g.0` 은 첫 range bf_id 만 보존 → 다른 bf_id 로 묶인 인접 paragraph 에 대해 부정확.
본 케이스: 좌측 단 그룹 [pi=6(bf=7) + pi=7~9(bf=4)] 머지로 g.0=7. composed[10].bf=4 비교 시 4 != 7 → partial_end 미설정 → 4면 stroke 단일 Rectangle → 하단 가로선 발생.
수정 (`src/renderer/layout.rs:1670-1699`)
`bf_id` 비교를 `stroke_sig` 비교로 변경:
```rust
let group_sig = stroke_sig(bf_id);
let prev_sig = stroke_sig(para_bf(first_pi - 1));
let next_sig = stroke_sig(para_bf(last_pi + 1));
if prev_sig.is_some() && prev_sig == group_sig { g.7 = true; }
if next_sig.is_some() && next_sig == group_sig { g.8 = true; }
```
머지와 동일 비교 기준으로 일관성 확보.
결과
Test plan
참고