Skip to content

render: route Canvas rendering through PageLayerTree#456

Closed
seo-rii wants to merge 17 commits intoedwardkim:develfrom
seo-rii:render-p2
Closed

render: route Canvas rendering through PageLayerTree#456
seo-rii wants to merge 17 commits intoedwardkim:develfrom
seo-rii:render-p2

Conversation

@seo-rii
Copy link
Copy Markdown
Contributor

@seo-rii seo-rii commented Apr 29, 2026

변경 요약

#165 에서 한 번에 들어갔던 렌더링 구조 변경을 P1 / P2로 나눠서 올리는 두 번째 단계입니다.

P1에서는 PageRenderTree 이후 단계에 PageLayerTree를 만들고, 이를 Rust native / WASM에서 확인할 수 있게 했습니다. 이번 PR은 그 다음 단계로, 기존 Canvas 렌더링 경로가 PageRenderTree를 직접 소비하지 않고 PageLayerTree를 통해 replay되도록 전환합니다.

목적은 새 renderer를 추가하는 것이 아니라, 이미 있는 Canvas renderer도 P1에서 만든 frontend/backend boundary를 타게 만드는 것입니다. 이렇게 하면 이후 CanvasKit, Skia, ThorVG 같은 renderer를 붙일 때도 모두 같은 PageLayerTree 입력을 기준으로 검증할 수 있습니다.

포함한 것

  • native Canvas renderer에 PageLayerTree replay 경로 추가
  • browser WebCanvasRendererPageLayerTree replay 경로 추가
  • public Canvas API를 기본적으로 layer replay 경로로 전환
    • renderPageCanvas
    • renderPageToCanvas
  • 기존 Canvas 경로를 parity / fallback 확인용 legacy API로 유지
    • renderPageCanvasLegacy
    • renderPageToCanvasLegacy
  • LayerBuilder가 leaf node의 child를 보존하도록 수정
    • leaf payload만 replay하고 child subtree가 빠지는 문제를 막기 위한 변경입니다.
  • Canvas layer replay와 legacy Canvas output을 비교하는 단위 테스트 추가
  • CI에서 Canvas layer parity test와 WASM target check를 실행하도록 보강
  • README / README_EN에 P2 단계 설명 추가

이번 PR에서 하지 않는 것

  • Skia backend 추가 안 함
  • CanvasKit backend 추가 안 함
  • ThorVG backend 추가 안 함
  • pixel diff / visual regression e2e는 이번 PR에 넣지 않음
    • 이 부분은 P3에서 별도 PR로 다루는 것이 좋다고 봅니다.
  • Canvas renderer의 모든 drawing primitive를 새 구조로 재설계하지 않음
    • 이번 PR은 기존 검증된 Canvas renderer를 PageLayerTree replay 입력으로 옮기는 단계입니다.

기존 SVG 기본 출력은 여전히 legacy 경로를 사용합니다. 이 PR에서 사용자-visible하게 바뀌는 부분은 public Canvas API가 PageLayerTree를 거쳐 replay된다는 점입니다.

관련 이슈

#364 #419 #165

테스트

  • cargo test canvas_layer_tree_matches_legacy --lib 통과
  • cargo check --lib 통과
  • cargo check --target wasm32-unknown-unknown --lib 통과
  • 웹(WASM) 렌더링 경로가 PageLayerTree 기반으로 빌드되는지 확인

스크린샷

이 PR은 Canvas replay 경로 전환과 parity test 추가가 중심이라 별도 스크린샷은 첨부하지 않았습니다.
pixel diff / visual regression 결과는 후속 P3 PR에서 다룹니다.

seo-rii and others added 17 commits April 28, 2026 19:15
- src/renderer/layout/utils.rs::find_bin_data 의 c.id == bin_data_id 가드 제거
  (c.id 는 storage_id, bin_data_id 는 인덱스 — 가드가 정상 케이스를 거짓 실패시킴)
- 1-indexed 인덱스 매칭 우선, 범위 밖일 때만 id 직접 검색 (HWPX 차트 sparse id 보존)
- 단위 테스트 5개: zero / 인덱스 매칭 (storage_id 다른 케이스, hwpspec.hwp 패턴) / 일반 케이스 / 차트 sparse id / 범위 밖
- cargo test --lib renderer::layout::utils::: 5 passed
- cargo build --lib + clippy 통과
- 수행/구현 계획서 + Stage 1 보고서 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
차트 회귀 우려 점검:
- HWPX 차트 sparse id (60001+) 는 항상 bin_data_content.len() 보다 큼 → 인덱스 범위 밖 → fallback id 검색 → 정확 매칭
- HWPX 일반 그림 (id=인덱스+1, 항상 일치) 은 인덱스 매칭으로 동일 결과
- 차트 회귀 위험 0

신규 단위 테스트 2개:
- find_bin_data_hwpx_realistic_layout_with_chart: 일반 BinData 1~3 + 차트 60001/60002 의 실제 push 패턴 모사, 양쪽 모두 정상 매칭 검증
- find_bin_data_hwp_hwpspec_page_bg_pattern: hwpspec.hwp 의 14개 BinData 모사, bin_data_id=1 이 storage_id=12 (BIN000C.png) 매칭 검증

검증:
- 단위 테스트 7/7 passed
- 전체 lib test: 1023 passed (1016 → +7)
- svg_snapshot: 6/6 passed (다른 샘플 무회귀)
- samples/hwpspec.hwp 1 페이지 SVG 재생성:
  * 정정 전: <image width="16" height="13"> (강제 stretch)
  * 정정 후: <image width="793.72" height="1121.56"> (정상 PNG, 1137 bytes 의 BIN000C)
  * 파일 크기 42 KB → 260 KB

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 자동 검증 종합: lib 1023 passed, svg_snapshot 6/6, clippy warning 0건, WASM 빌드 통과
- 트러블슈팅 문서 갱신 (bin_data_id_index_mapping.md):
  * 2026-04-20 회귀 origin (Task edwardkim#195) 이력 추가
  * 2026-04-28 재정정 (가드 제거 + sparse id 분기)
  * 추가 교훈 — 가드/fallback 추가 시 트러블슈팅 정독, PR 검토 절차 강화
- 최종 보고서 + 오늘할일 갱신
- 별개 결함 (페이지 20 이미지 이중 출력) 은 별도 이슈로 처리 예정

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@seo-rii seo-rii marked this pull request as ready for review April 29, 2026 10:41
edwardkim added a commit that referenced this pull request Apr 30, 2026
- mydocs/pr/pr_456_review.md (P2 cherry-pick 검토, SVG 100% byte 동일)

검증: 1075 passed (+5 Canvas parity test) + svg_snapshot 6/6 + issue_418 1/1 + clippy 0
WASM: 4,206,022 bytes (+19,741, paint 모듈 Canvas replay 추가)
광범위 byte 비교: 305/305 byte 동일 (SVG legacy 경로 0 영향) ✅

본질 (PR #419 의 P2):
- Canvas 렌더 경로를 PageLayerTree replay 로 전환
- legacy 경로는 renderPageCanvasLegacy 로 보존 (fallback)
- LayerBuilder leaf children 보존 정정
- Canvas parity test 추가 (CI 통합)

시각 판정: 통합 검증 (PR #454 + #457 + #461 + #456 머지 후 작업지시자 직접)
edwardkim added a commit that referenced this pull request Apr 30, 2026
@edwardkim
Copy link
Copy Markdown
Owner

@seo-rii 님 PR 감사드립니다. 메인테이너가 cherry-pick 으로 devel 에 적용 완료했습니다.

PR #419 (P1) 에서 만들어주신 PageLayerTree generation API 를 Canvas 렌더 경로의 default 로 전환한 P2 — 외부 backend 도입 토대가 정확히 구축되었습니다.

처리

작성자 attribution 보존 본질 6 commits 분리 cherry-pick (PR #419 commits + Task #416 commits 11 개는 이미 devel 흡수):

  • 5422222 (← f1caa55) feat: replay layer trees through canvas recorder
  • e5c3887 (← 66e4e1b) feat: replay layer trees through web canvas
  • afda14a (← 4e56eb1) feat: route public canvas through layer replay
  • 873e038 (← df02a3c) test: gate canvas layer parity in ci
  • 9c4a511 (← f9243ef) test: check wasm target in ci
  • f5708a7 (← bbc3411) fix: preserve leaf children in layer lowering

devel 머지 commit: 109bb04

검증

광범위 byte 비교 — 매우 깔끔

10 샘플 / 305 페이지 SVG 비교: 305/305 byte 단위 동일 (100%)

→ SVG legacy 경로 영향 0. PR 본문 명시 ("기존 SVG 기본 출력은 여전히 legacy 경로를 사용") 정확 검증.

본 PR 의 좋은 점

  1. PR render: introduce PageLayerTree generation API #419 (P1) 의 정확한 후속 P2: 외부 backend 도입 토대 + 검증 게이트 (Canvas parity test) 동시 정합
  2. legacy / replay 분리: renderPageCanvasLegacy API 보존 → 사용자 fallback / 비교 가능
  3. 메인테이너 안내 7항목 (이슈 다양한 렌더러 지원을 위한 PageLayerTree 생성 API 추가 제안 #364) 정확 대응: P1 + P2 분리 + opt-in / default 전환 정책 모두 부합
  4. Canvas parity test 추가: legacy / replay 같은 출력 자동 검증 (CI 통합) — 향후 회귀 게이트
  5. SVG byte 단위 동일: 기존 SVG 사용자에게 영향 0 — 위험 분산
  6. LayerBuilder 정정: leaf node child subtree 보존 — 본질 결함 사전 식별 + 정정

통합 시각 검증 정책

작업지시자 결정으로 PR #454 + #457 + #461 + #456 모두 머지된 현재 상태에서 통합 시각 검증 진행 예정. 본 PR (#456) 의 Canvas 경로 전환은 SVG byte 단위 동일이라 위험 매우 낮음 — 통합 검증의 핵심은:

  1. PR Task #452: 단락 마지막 줄 trailing line_spacing 정합 (exam_kor pi=1↔pi=2) #454/Task #455: 인라인 글상자(tac=true + TextBox) 가 있는 줄의 외부 본문 텍스트 누락 수정 #457/Task #459: 다단 후속 페이지 LINE_SEG vpos-reset 단 경계 미인식 수정 #461 의 누적 정정 통합 검증 (paragraph_layout / 글상자 / vpos-reset / 셀 leakage 등)
  2. 본 PR (render: route Canvas rendering through PageLayerTree #456) 의 Canvas 경로 전환 — rhwp-studio (WASM Canvas) 에서 default API 가 PageLayerTree replay 로 정상 동작하는지

후속 P3 안내

작성자 본문 명시:

"pixel diff / visual regression e2e 는 이번 PR 에 넣지 않음 — 이 부분은 P3 에서 별도 PR 로 다루는 것이 좋다고 봅니다."

→ P3 도 같은 P1/P2 패턴 (분리 PR + 작은 단위 회전) 으로 진행 환영합니다. P1/P2 의 정확한 분리 + Canvas parity test 추가 + LayerBuilder 본질 정정 모두 좋은 작업이었습니다. 감사합니다.

@edwardkim edwardkim closed this Apr 30, 2026
jangster77 added a commit to jangster77/rhwp that referenced this pull request Apr 30, 2026
…Canvas→LayerTree 반영 (Task edwardkim#460 기반)

- upstream/devel 46 commits 병합 (PR edwardkim#446 set_field fix ~ PR edwardkim#456 Canvas→LayerTree)
- 소스 파일 자동 병합 성공 (layout.rs, paragraph_layout.rs, engine.rs)
- orders/20260430.md add/add 충돌만 수동 해소 (Task edwardkim#460 섹션 + PR edwardkim#450 섹션 통합)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request Apr 30, 2026
…7 commits)

본 PR 은 PR #456 (PageLayerTree replay 전환 P2) 후속 P3 검증 레이어:
- rhwp-studio E2E (canvas-render-diff.test.mjs)
- GitHub Actions Render Diff workflow
- legacy Canvas vs PageLayerTree replay Canvas 픽셀 diff 자동 검증

7 commits 분리 cherry-pick (test + diagnostics + docs + CI runner +
보안 hardening 3건). 변경 영역: JS E2E + CI workflow + Vite 설정 +
문서 (Rust 변경 0).

검증: cargo test --lib 1102 passed, svg_snapshot 6/6, issue_418 1/1,
issue_501 PASS, clippy 0건.

작업지시자 정책: ios/devel 처럼 skia 쪽 렌더러도 별도 브랜치로
운영하여 위험도 낮추는 방법 고려 중. 본 검증 인프라가 향후 별도
backend 실험 시 backend 별 회귀 검출 도구로 활용 가능.

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