render: route Canvas rendering through PageLayerTree#456
render: route Canvas rendering through PageLayerTree#456seo-rii wants to merge 17 commits intoedwardkim:develfrom
Conversation
- 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>
- 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 머지 후 작업지시자 직접)
…ry-pick @seo-rii 6 commits)
|
@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 흡수):
devel 머지 commit: 검증
광범위 byte 비교 — 매우 깔끔10 샘플 / 305 페이지 SVG 비교: 305/305 byte 단위 동일 (100%) ✅ → SVG legacy 경로 영향 0. PR 본문 명시 ("기존 SVG 기본 출력은 여전히 legacy 경로를 사용") 정확 검증. 본 PR 의 좋은 점
통합 시각 검증 정책작업지시자 결정으로 PR #454 + #457 + #461 + #456 모두 머지된 현재 상태에서 통합 시각 검증 진행 예정. 본 PR (#456) 의 Canvas 경로 전환은 SVG byte 단위 동일이라 위험 매우 낮음 — 통합 검증의 핵심은:
후속 P3 안내작성자 본문 명시:
→ P3 도 같은 P1/P2 패턴 (분리 PR + 작은 단위 회전) 으로 진행 환영합니다. P1/P2 의 정확한 분리 + Canvas parity test 추가 + LayerBuilder 본질 정정 모두 좋은 작업이었습니다. 감사합니다. |
…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>
…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>
변경 요약
#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입력을 기준으로 검증할 수 있습니다.포함한 것
PageLayerTreereplay 경로 추가WebCanvasRenderer에PageLayerTreereplay 경로 추가renderPageCanvasrenderPageToCanvasrenderPageCanvasLegacyrenderPageToCanvasLegacyLayerBuilder가 leaf node의 child를 보존하도록 수정이번 PR에서 하지 않는 것
PageLayerTreereplay 입력으로 옮기는 단계입니다.기존 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통과PageLayerTree기반으로 빌드되는지 확인스크린샷
이 PR은 Canvas replay 경로 전환과 parity test 추가가 중심이라 별도 스크린샷은 첨부하지 않았습니다.
pixel diff / visual regression 결과는 후속 P3 PR에서 다룹니다.