Skip to content

Task #287: 빈 runs comp_line 의 TAC 수식 인라인 처리 추가#289

Merged
edwardkim merged 11 commits into
edwardkim:develfrom
planet6897:local/task287
Apr 24, 2026
Merged

Task #287: 빈 runs comp_line 의 TAC 수식 인라인 처리 추가#289
edwardkim merged 11 commits into
edwardkim:develfrom
planet6897:local/task287

Conversation

@planet6897

Copy link
Copy Markdown
Contributor

요약

  • samples/exam_math_8.hwp 의 박스 내 큰 cases 수식 a_{n+1} = {...} 이 박스 좌상단((71.80, 147.38))에 찍혀 테두리·선행 텍스트와 겹치던 버그를 해결 (closes 수식 SVG 레이아웃: 큰 디스플레이 TAC 수식이 줄 상단(y=col_area.y)으로 올라감 (exam_math_8) #287)
  • src/renderer/layout/paragraph_layout.rs 의 run 루프 종료 직후에 빈 runs comp_line 의 TAC Equation 인라인 처리 블록을 추가 (+63 줄). 큰 수식이 속한 ls(line_segs[1])는 runs=[] 로 조립되어 기존 인라인 경로를 못 탔고, shape_layout display 경로로 떨어져 eq_y = col_area.y 로 고정되던 것이 원인이었음
  • 결과: 수식이 (133.27, 188.29) — 박스 내부 line 1 위치로 정상 배치. shape_layout 중복 렌더도 제거됨

배경과 원인

초기 가설("has_tac_shape 조건 누락 + .max(y) clamp")은 단계 1 실측으로 틀림이 확인됨. 임시 덤프(RHWP_DUMP_287) 로 본 comp_line 별 상태:

[287] para=0 line=1 y=172.69 raw_lh=54.60 line_h=54.60 baseline=32.76 max_fs=0.00
       tac_offsets_px=[(11,9.8,2,Eq), (17,327.6,3,Eq)] runs=[]
  • line 1 의 y=172.69 는 ls[1] vpos 기반으로 정확히 계산됨 (누적 y 문제 없음)
  • 그러나 runs=[] 이라 for run in comp_line.runs 루프가 돌지 않음 → 그 안의 TAC 인라인 처리 블록이 실행되지 않음
  • [287-eq] para=0 ci=3 로그 부재로 인라인 경로 미진입 확정

접근

  • (A) compose_paragraph 에 vpos 파이프라인 전파 → composer + layout + render_tree + 대규모 스냅샷 재검증 필요. 조판 엔진 리팩터링급 범위라 본 타스크 초과
  • (C, 채택) 빈 runs comp_line 에서도 그 줄이 소유한 TAC 수식을 인라인 처리 → 수정 규모 작고 근본적
if comp_line.runs.is_empty() && !tac_offsets_px.is_empty() {
    let line_start_char = comp_line.char_start;
    let line_end_char = composed.lines.get(line_idx + 1)
        .map(|l| l.char_start).unwrap_or(usize::MAX);
    let mut inline_x = col_area.x + effective_margin_left;
    for &(tac_pos, tac_w, tac_ci) in &tac_offsets_px {
        if tac_pos < line_start_char || tac_pos >= line_end_char { continue; }
        if let Some(Control::Equation(eq)) = para.and_then(|p| p.controls.get(tac_ci)) {
            // ... EquationNode 생성 (기존 인라인 분기와 동일 로직) ...
            tree.set_inline_shape_position(section_index, para_index, tac_ci, inline_x, eq_y);
            inline_x += tac_w;
        }
    }
}
  • 줄 char 범위 [comp_line.char_start, next.char_start) 로 이 줄 소유 TAC 필터링
  • tree.set_inline_shape_position 등록으로 shape_layout.rs:133-182 display 경로의 중복 렌더 차단

변경 전/후 (SVG transform)

수식 변경 전 변경 후
큰 cases 수식 (exam_math_8) translate(71.80, 147.38) (col_area 원점) translate(133.27, 188.29) (line 1)

회귀 영향

수정 전/후 SVG diff:

파일 변화 해석
exam_math_8.svg 큰 수식 이동 본 타스크 목적
exam_math_008.svg (page 8) 동일 "박스 내 큰 수식" 구조 자동 개선 텍스트 유실 없음, SVG 순서만 변경
exam_math_012.svg cell-clip-{112→113} 등 ID shift tree.next_id() 추가 호출 영향, 내용·좌표 동일
equation-lim.svg y 132.27 → 133.15 (+0.88 px) display → 인라인 경로 전환에 따른 baseline 미세 조정
나머지 19개 exam_math 페이지 완전 동일

한계 (Phase 2 로 분리)

PDF 대비 수식 x 가 약 30-50 px 좌측 치우침 (현재 x=133.27 vs PDF x≈162-182). HWP 문단이 (가) ... \t <수식> 처럼 탭 제어문자로 들여쓰기됐으나 빈 runs 줄에서는 탭 처리 로직(char_x_map, find_next_tab_stop)이 돌지 않음. tab_stops=1 (pos=13600 HU=181 px) 존재하지만 활용 안 됨.

완전 일치는 compose_lines 수정(ls 선행 \t 보존) 혹은 빈 runs 전용 휴리스틱 필요 → 범위 고려해 Phase 2 #288 로 분리.

산출물

  • 계획서: mydocs/plans/task_m100_287{,_impl}.md
  • 단계별 보고서: mydocs/working/task_m100_287_stage{1,2,3}.md
  • 최종 보고서: mydocs/report/task_m100_287_report.md
  • 샘플: samples/exam_math_8.{hwp,pdf}
  • orders 갱신: mydocs/orders/20260424.md

Test plan

  • cargo test --lib renderer (291/291)
  • cargo test --lib equation (48/48)
  • cargo test --test svg_snapshot (3/3)
  • cargo clippy --lib -- -D warnings clean
  • 시각 회귀: exam_math.hwp (20페이지), equation-lim.hwp 수동 diff 확인
  • 타겟: exam_math_8.hwp 가 박스 내부에 배치됨을 SVG transform 좌표로 확인
  • (작업지시자) 브라우저·PDF 최종 시각 비교

관련 이슈

planet6897 and others added 4 commits April 24, 2026 14:31
- samples/exam_math_8.{hwp,pdf}: 재현 샘플 (박스 내 큰 cases 수식)
- mydocs/plans/task_m100_287{,_impl}.md: 수행·구현계획서
- mydocs/working/task_m100_287_stage1.md: 단계 1 조사 보고서

조사 결과 (계획서 단계 2 갱신 포함):
- 초기 가설 "has_tac_shape 조건 누락 + .max(y) clamp" 는 단계 1 덤프로 틀림 확인
- 진짜 원인: 큰 수식이 속한 comp_line 이 runs=[] (빈 runs) 이고 TAC 인라인 처리
  블록이 run 루프 안에 있어 빈 runs 줄에서 실행되지 않음 → shape_layout display
  경로로 떨어져 eq_y = col_area.y 로 고정
- 구현계획서 단계 2 섹션을 "빈 runs comp_line 의 TAC 인라인 처리 추가" 로 갱신
- (A) vpos 파이프라인 전파는 조판 엔진 리팩터링급으로 범위 초과 → (C) 채택

Refs edwardkim#287

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/renderer/layout/paragraph_layout.rs (+63): run 루프 종료 직후에
  comp_line.runs.is_empty() && !tac_offsets_px.is_empty() 조건 분기 추가
- 줄 char 범위 [comp_line.char_start, next.char_start) 로 필터링
- 기존 인라인 TAC 분기와 동일 EquationNode 생성 로직 사용
- tree.set_inline_shape_position 등록으로 shape_layout display 경로 중복 렌더 차단

검증:
- samples/exam_math_8.hwp: 큰 수식 transform (71.80,147.38) → (133.27,188.29)
- cargo test --lib renderer: 291 passed
- cargo test --lib equation: 48 passed
- cargo test --test svg_snapshot: 3 passed
- cargo clippy --lib -- -D warnings: clean

회귀 diff (수정 전/후):
- exam_math_008.svg: 동일 구조 자동 개선 (텍스트 유실 없음, SVG 순서만 변경)
- exam_math_012.svg: tree.next_id() 추가 호출로 ID 1 shift (내용·좌표 동일)
- equation-lim.svg: y +0.88 px (display → 인라인 경로 baseline 미세 조정)
- 나머지 19 페이지 완전 동일

Refs edwardkim#287

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- mydocs/working/task_m100_287_stage3.md: 단계 3 보고서
- GitHub edwardkim#288 등록: 빈 runs 줄의 TAC 수식 x 에 탭 반영 (Phase 2)

PDF ↔ SVG 시각 대조:
- 본래 버그(박스 좌상단 (71.80,147.38) 고정) 해결 확인
- 남은 차이: x=133.27 vs PDF x≈162-182 (약 30-50 px 좌측 치우침)
- 원인: HWP 문단이 "(가) ... \t <수식>" 처럼 탭으로 들여쓰기 되어있는데
  빈 runs 줄에서는 탭 처리가 돌지 않음. tab_stops=1 존재하지만 char_x_map
  이 빈 runs 에서 생성되지 않아 사용 불가.
- 완전 일치는 compose_lines 수정 또는 휴리스틱 필요 → 본 타스크 범위 초과
- 작업지시자 판단 "B" 채택: 현재 상태로 단계 4 진행, Phase 2 별도 이슈

임시 덤프 로그 제거 (단계 2 에서 단계 3 진단용으로 남긴 3 지점):
- paragraph_layout.rs L730 부근 (comp_line 루프 시작부)
- paragraph_layout.rs L1586 부근 (인라인 수식 분기)
- paragraph_layout.rs L1960 부근 (빈 runs TAC 처리 블록)

Refs edwardkim#287 edwardkim#288

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- mydocs/report/task_m100_287_report.md: 최종 결과 보고서
- mydocs/orders/20260424.md: Task edwardkim#287 섹션 추가 + 종료/대기 이슈 갱신

이 타스크의 실질적 가치:
- 초기 가설("has_tac_shape 조건 누락")이 단계 1 덤프로 틀림 확인 → 구현계획서
  단계 2 를 "빈 runs comp_line TAC 인라인 처리 추가" 로 방향 전환
- (A) vpos 파이프라인 전파의 유혹을 회피하고 범위를 좁힌 판단: 조판 엔진
  리팩터링급 작업을 한 타스크에서 무리하게 떠안았다면 회귀 폭증 + 릴리즈 지연
- 완전 일치(PDF x 정확 일치)를 Phase 2 로 분리하여 본 타스크 완결성 확보

Closes edwardkim#287

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@planet6897 planet6897 changed the title Local/task287Task #287: 빈 runs comp_line 의 TAC 수식 인라인 처리 추가 Task #287: 빈 runs comp_line 의 TAC 수식 인라인 처리 추가 Apr 24, 2026
planet6897 and others added 7 commits April 24, 2026 14:41
- mydocs/plans/task_m100_288.md: 수행계획서
- mydocs/working/task_m100_288_stage1.md: 단계 1 조사 보고서

조사 결과 (임시 examples/task288_probe.rs 로 문단 원본 덤프):
- para.text = "(가) 모든 자연수 에 대하여\n\n이다." — \t 문자 존재하지 않음
- line 1 의 runs=[] 는 연속된 \n\n 사이에 큰 수식 TAC 이 삽입된 자연스러운 구조
- 이슈 원문의 접근 (A: 휴리스틱, B: compose \t 보존) 모두 전제 무효

단계 2 에서 PDF 실측으로 규칙 역추정 예정.

Refs edwardkim#288

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- mydocs/working/task_m100_288_stage2.md: 단계 2 측정 보고서

PDF content stream 의 Tm (text matrix) 을 Node.js zlib 으로 직접 추출:

| 요소         | PDF Tm.e | SVG x  | SVG/PDF 비율 |
| "("          | 481      | 102.07 | 0.2122       |
| 큰 수식 첫   | 627      | 133.27 | 0.2125       |

- 모든 요소에서 비율 0.2125 로 일치
- PDF 내 수식이 "(" 보다 146 단위 오른쪽, SVG 는 31.2 px (환산 31.03)
- 오차 0.17 px — PDF 와 사실상 정확히 일치

결론: edwardkim#287 수정만으로 이미 PDF 와 일치. edwardkim#288 은 실제 증상이 없는 이슈.
  - 원래 "PDF x≈162-182" 추정은 PDF 이미지 눈대중에서 나온 오판
  - 이슈 edwardkim#288 을 "not a bug (edwardkim#287 수정으로 이미 PDF 와 일치)" 으로 close 예정

Refs edwardkim#288

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- mydocs/report/task_m100_288_report.md: 최종 결과 보고서
- mydocs/orders/20260424.md: Task edwardkim#288 섹션 추가 + 종료 이슈 갱신

이 타스크의 실질적 가치:
- PDF content stream 실측으로 "문제 자체가 없음" 을 수치로 판명
- 눈대중 비교 대신 Tm 직접 추출 → 10-50 px 급 오판 회피
- edwardkim#287 을 (C) 빈 runs TAC 인라인 처리로 좁게 수정한 판단이 결과적으로
  완결적이었음 확인 — Phase 2 로 분리했던 것 자체가 불필요한 분리였음
- 부정 확인(탭 가설 부인) 직후 "증상 자체 유무" 를 재검증하는 루프의 필요성

코드 변경 없음. examples/task288_probe.rs 임시 파일은 작성→제거.

Closes edwardkim#288

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
원격 local/task287 이 devel 의 edwardkim#283 (PR edwardkim#285) 머지를 포함해 7 commit 앞섰고
로컬이 edwardkim#288 3 commit 을 앞서던 상태 → 양쪽 합치는 merge.

충돌: mydocs/orders/20260424.md 의 "등록·대기" 섹션
해결:
- Task edwardkim#283 섹션 번호 ## 3 → ## 4 (원격 추가분)
- Task edwardkim#288 섹션 번호 ## 4 → ## 5 (로컬 추가분)
- "종료" 리스트에 edwardkim#283 추가 (실제 devel 에 PR edwardkim#285 로 merge 완료)
- "등록·대기" 비움 (오늘 사이클 내 모든 이슈 종료)

edwardkim#283 소스 변경 (src/renderer/equation/{canvas_render,layout,svg_render}.rs)
및 산출물은 원격에서 이미 commit 되어 그대로 포함.

Refs edwardkim#287 edwardkim#288 edwardkim#283

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@edwardkim edwardkim left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Approved. 🎉

@planet6897 님, 두 연속 타스크 (#287, #288) 모두 완결 품질 훌륭합니다.

평가 포인트

  • 초기 가설 기각 후 방향 전환 — RHWP_DUMP_287 로그 실측으로 'has_tac_shape + clamp' 가설을 버리고 진짜 원인 (빈 runs + 인라인 경로 미진입) 발견
  • 범위 판단 우수 — (A) vpos 파이프라인 전파 (조판 엔진 리팩터링급) 회피, (C) 63줄 추가로 근본 해결
  • Phase 2 불필요 확인 — #288을 PDF content stream Tm 실측으로 'not a bug' 확정 (비율 0.2125 일치, 오차 0.17px). 눈대중 오판 회피. 보고서의 교훈 한 줄이 인상적:

    '부정 확인(탭 가설 부인) 직후 "증상 자체 유무"를 재검증하는 루프의 필요성'

  • 기존 인라인 로직 재사용 — EquationNode 생성 코드 완전 동일. 일관성 보장
  • tree.set_inline_shape_position 호출 — shape_layout display 경로 중복 렌더 차단. 핵심 방어

메인테이너 검증

항목 결과
CI + CodeQL (rust/js/python) ✅ 전부 SUCCESS
cargo test --lib ✅ 983 / 0 / 1 ignored
cargo test --test svg_snapshot ✅ 6 / 0
cargo clippy / wasm32 ✅ clean
WASM Docker 빌드 ✅ 성공
rhwp-studio 브라우저 시각 검증 ✅ 박스 내부 line 1 위치 정상 배치 확인

Merge 진행합니다.

@edwardkim edwardkim merged commit 8e2c352 into edwardkim:devel Apr 24, 2026
6 checks passed
edwardkim added a commit that referenced this pull request Apr 24, 2026
- 작성자: @planet6897 (Task #287, PR #289)
- Merge commit: 8e2c352
- 이슈 #287 closed (#288은 이미 "not a bug"로 작성자 close)

변경:
- src/renderer/layout/paragraph_layout.rs +63: 빈 runs comp_line TAC Equation 인라인 블록
- samples/exam_math_8.{hwp,pdf} 신규

검증:
- CI + CodeQL (rust/js/python): 전부 SUCCESS
- cargo test --lib: 983 passed / 0 failed / 1 ignored
- svg_snapshot: 6 passed
- WASM Docker 빌드 + rhwp-studio 브라우저 시각 검증 성공

평가: 초기 가설 기각 + Phase 2 (#288) PDF Tm 실측으로 "not a bug" 확정. 눈대중 오판 회피.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request Apr 24, 2026
 #297)

- 작성자: @planet6897 (Task #297, PR #300, 오늘 6번째 기여)
- Merge commit: 0e3fb02 (admin merge, orders 3구간 충돌 직접 해결)
- 이슈 #297 CLOSED

처리 절차:
- PR 브랜치에 origin/devel 머지 → orders 섹션 3구간 해결 (#295 "## 7", #296 "## 8", #297 "## 9")
- planet6897/task297 에 push
- 재승인 + admin merge

변경 (1파일):
- src/renderer/layout/table_layout.rs +5 -2:
  - VertRelTo::Page => (col_area.y, col_area.height)  [쪽 본문 영역]
  - VertRelTo::Paper => (0, page_h_approx)  [용지 전체, 유지]
  - HWP 스펙 Page=쪽 본문, Paper=용지 전체 반영

성과:
- pi=22 "* 확인 사항" 박스 y: 1371.5 → 1224.07 (PDF 1226.5 ±2 일치)
- 145 샘플 중 본문 Page 표 13건 + 바탕쪽 5건 회귀 스캔 완료 (의도 범위 외 무회귀)

검증:
- cargo test --lib: 992 passed
- svg_snapshot: 6 passed (golden 유지)
- 실제 SVG y 좌표 확인: 1224.07px (PDF 일치)

#295#297 연결 모범 사례: PR #298 리뷰 중 사전 존재 버그로 분리 → 1시간 만에 PR #300 해결.
초기 가설(바탕쪽 Paper) 폐기 → pdftotext 실측으로 근본 원인(enum 미구분) 발견 → 1줄 수정.

===== 오늘 9번째 PR 머지 =====
#284 #285 #266 #273 #277 #278 #289 #292 #298 #300
+ 메인테이너 핀셋 #296

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request Apr 25, 2026
- 작성자: @planet6897 (Task #301, PR #303)
- Merge commit: 798b845 (Task #287/PR #289 회귀 수정)
- 이슈 #301 CLOSED

변경 (1파일 1줄):
- src/renderer/layout/table_layout.rs +7 -2:
  - Equation 분기에 tree.get_inline_shape_position() 가드 추가
  - paragraph_layout(Task #287) 이 이미 렌더했으면 직접 emit 스킵

테스트:
- tests/issue_301.rs (신규, +44): z_table_equations_rendered_once
  - 0.1915/0.3413/0.4332 각 1회, 0.4772는 본문 포함 2회

검증:
- cargo test --lib: 992 passed
- svg_snapshot: 6 passed (golden 유지)
- 실제 SVG z-table 출현 횟수: 작성자 주장 정확히 일치
- WASM Docker 빌드 + rhwp-studio 브라우저 시각 검증: 성공

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@planet6897 planet6897 deleted the local/task287 branch April 30, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants