render: add native Skia PNG raster backend#599
Conversation
PR #599 (refs #536, @seo-rii) 1차 검토 — render P4 native Skia PNG raster backend: - 본 환경 정체성 정합 (project_dtp_identity — DTP 엔진 + 다층 레이어 토대) - PR base skew 73 commits (eaac8bd, 5/4 PR #563 후속) — 단순 머지 시 본 사이클 cherry-pick 처리분 모두 revert 위험 - 그러나 본질 영역 (src/renderer/skia/ + layer_renderer.rs + image_conv.rs) 이 본 사이클 처리분과 0 중첩 → commit 단위 cherry-pick 가능 - 9 commits 순차 cherry-pick test: 모두 충돌 0 + cargo test --lib --release 1134 passed (회귀 0) + cargo test --features native-skia skia 20 passed + clippy 0건 - native-skia feature gate (기본 빌드 영향 없음, opt-in) 권장 처리: 옵션 A — 9 commits 순차 cherry-pick (단순 머지 절대 금지) + 결정적 검증 + Skia feature 테스트 + WASM check + PNG 내보내기 게이트웨이.
…션 + export-png CLI + 매뉴얼 PR #599 (Task #588 후속, refs #536) 의 Skia native PNG raster backend cherry-pick 후 메인테이너 정정 영역. 5개 영역 정합 처리: 1. **Skia 한글 폰트 fallback chain** (renderer.rs): - Noto Sans KR / Noto Serif KR / Nanum / Apple SD Gothic Neo / Apple Myungjo / Batang / 바탕 / Malgun Gothic / 맑은 고딕 등 추가 - SVG 의 CSS font chain 과 동일한 한글 폴백 폰트 순서 2. **--font-path 동적 폰트 로딩** (with_font_paths API): - SkiaLayerRenderer 에 custom_typefaces HashMap 추가 - ttfs 디렉토리의 한컴 전용 폰트 (HY견명조 등) 동적 로드 - SVG 의 --font-path 와 동일 패턴 3. **char 단위 fallback 렌더링** (공백 두부 정정): - text 를 char 단위로 분해, primary typeface 가 글리프 미보유 (unichar_to_glyph==0) 시 chain 의 다른 typeface 시도 - 모두 미보유 시 visible 글리프 그리지 않음 (NBSP/U+2007/U+200B 등 두부 방지) - measure_str 으로 정확한 advance 진행 4. **VLM 옵션 (AI 파이프라인 + Vision-Language Model 연동)**: - --vlm-target claude (1568 longest edge / 1.15 MP, Claude Vision 정합) - --scale <배율> (직접 배율) - --max-dimension <픽셀> (한 변 한도, 자동 scale 계산) - max_dimension + max_pixels 결합 자동 scale + 0.995 안전 마진 - PngExportOptions / VlmTarget 타입 정의 5. **export-png CLI 명령** (main.rs): - --output / --page / --font-path / --scale / --max-dimension / --vlm-target - native-skia feature gate (기본 빌드 영향 0) - DocumentCore::render_page_png_native_with_export_options API 호출 6. **매뉴얼 (한글 + 영문 동기화)**: - mydocs/manual/export_png_command.md - mydocs/eng/manual/export_png_command.md 7. **PNG 게이트웨이 도구**: - examples/pr599_png_gateway.rs 후속 이슈: - #613 (VLM 프리셋 확장 — GPT-4V / Gemini / Qwen-VL / LLaVA) - #614 (DPI 메타데이터 옵션 — PNG pHYs chunk) 검증: - cargo test --lib --release 1134 passed (회귀 0) - cargo test --features native-skia skia 20 passed - cargo clippy --release --features native-skia 0건 - 광범위 페이지네이션 회귀 sweep: 164 fixture / 1,614 페이지 / 회귀 0 - VLM 옵션 게이트웨이: 5개 옵션 조합 모두 정상 동작 (Claude 1.14M ≤ 1.15M ✓) - 시각 판정 ★ 통과 (SVG/PNG 한글 + 공백 정상 표시)
…efs #536 — @seo-rii 9 commits + 5개 영역 정정 + 시각 판정 ★ 통과) PR #599 (refs #536, @seo-rii) — render P4 native Skia PNG raster backend: - Skia 본질 cherry-pick (9 commits): src/renderer/skia/ + layer_renderer.rs + image_conv.rs 신규 영역 (본 사이클 처리분과 0 중첩) - 메인테이너 후속 정정 (5개 영역): 1. Skia 한글 fallback chain (Noto Sans KR / Nanum 등) 2. --font-path 동적 로딩 (with_font_paths API, SVG 패턴 정합) 3. char 단위 fallback (공백 두부 정정 — NBSP/U+2007/U+200B 방지) 4. VLM 옵션 (--vlm-target claude + --scale + --max-dimension, AI 파이프라인 + Vision-Language Model 연동) 5. export-png CLI 명령 + 매뉴얼 (한글 + 영문 동기화) 검증: - cargo test --lib --release 1134 passed (회귀 0) - cargo test --features native-skia skia 20 passed - clippy 0건 - WASM 4,581,465 bytes (PR #593 baseline +0 — feature gate 정합 입증) - 광범위 페이지네이션 회귀 sweep: 164 fixture / 1,614 페이지 / 회귀 0 - VLM 옵션 게이트웨이: Claude 898×1269 = 1.14 MP ≤ 1.15 MP ✓ 후속 이슈 등록: - #613 (VLM 프리셋 확장 — GPT-4V / Gemini / Qwen-VL / LLaVA) - #614 (DPI 메타데이터 옵션 — PNG pHYs chunk) 시각 판정 ★ 통과 (SVG/PNG 한글 + 공백 정상 표시). refs #536 (멀티 렌더러 지원 트래킹 이슈, OPEN 유지).
|
@seo-rii Thanks for the P4 stage — native Skia PNG raster backend ✨ The 9 essential commits have been cherry-picked into devel ( Merged
Maintainer follow-up fixes (
|
|
영문 댓글로 답변드린 점 양해 부탁드립니다 — 본 프로젝트 컨트리뷰터 분들께는 한글로 답변드리는 것이 정합인데, 본 PR 의 본질 영역이 영문 코드/주석 중심이라 영문으로 작성했습니다. 한글로도 같이 정리해드립니다. 처리 결과@seo-rii 님 P4 단계 (native Skia PNG raster backend) cherry-pick 완료되었습니다 (devel merge Cherry-pick
결정적 검증
메인테이너 후속 정정 (5개 영역, `876d820`)PR #599 본질만으로는 본 환경 한컴 fixture 가 정상 표시되지 않아 5개 영역 추가 정정. 향후 PR 에서 같은 패턴 적용에 참고 부탁드립니다. 1. Skia 한글 폰트 fallback chain (`renderer.rs::draw_text`)`4cf787f` (use font fallback in native skia text) 의 `["DejaVu Sans", "Arial", "sans-serif"]` chain 에 한글 폰트 추가 — Noto Sans KR / Noto Serif KR / Nanum Gothic / Nanum Myeongjo / Malgun Gothic / 맑은 고딕 / Batang / 바탕 / Apple SD Gothic Neo / AppleMyungjo 등. → SVG 의 CSS font chain 과 동일 패턴. CharShape.font_family (HY견명조 등) 가 시스템에 없을 때 한글 글리프 미보유 폰트로 fallback → 사각형(豆腐) 표시 결함 정정. 2. `--font-path` 동적 폰트 로딩 (`with_font_paths` API)`SkiaLayerRenderer::with_font_paths(&[PathBuf])` 추가:
3. char 단위 fallback (공백 두부 정정)단일 `canvas.draw_str(text, ...)` 호출이 NBSP (U+00A0) / FIGURE SPACE (U+2007) / ZERO WIDTH SPACE (U+200B) 등을 두부로 표시. char 단위 loop 으로 변경 — primary typeface 가 글리프 미보유 (`unichar_to_glyph==0`) 시 chain 의 다른 typeface 시도, 모두 미보유 시 visible glyph 그리지 않고 일반 공백 너비로 advance. 4. VLM 옵션 (AI 파이프라인 + Vision-Language Model 연동)`PngExportOptions` + `VlmTarget::Claude` 추가: ```bash 자동 scale 계산 — max_dimension + max_pixels 결합 (둘 다 한도 안) + 0.5% 안전 마진 (ceil + 부동소수점 오차). 다른 VLM 프리셋 (GPT-4V / Gemini / Qwen-VL / LLaVA) 은 #613 후속 task. 5. `export-png` CLI 명령 + 매뉴얼`src/main.rs::export_png` 추가 (native-skia feature gate, 기본 빌드 영향 0). 매뉴얼:
`--dpi` PNG pHYs chunk 메타데이터는 #614 후속 task. 향후 P5+ 단계 참고PR 본문 §"비목표" 영역 (complex text shaping parity / 완전한 equation native replay / CanvasKit / Skia visual regression fixture pipeline) 은 그대로 유지. 위 5개 영역은 본 환경 PNG backend 가 사용 가능한 수준으로 만들기 위한 최소 정합이며, 더 광범위한 text shaping (kerning / GSUB / GPOS) 작업은 별도 영역으로 정합. `unichar_to_glyph` per-char fallback 방식이 Skia 의 `make_text_blob` shaping 또는 harfbuzz 통합과 비교해서 더 좋은 idiomatic 패턴이 있다면 알려주세요. 향후 다시 검토 가능합니다. P3 (PR #498) → P4 (본 PR) 흐름의 일관성 + DTP 엔진 정체성 (`project_dtp_identity` — 다층 레이어 / WebGPU / 마스터 페이지 인프라 토대) 정합 우수했습니다. 감사합니다. |
- 처리 보고서 추가: mydocs/pr/archives/pr_599_report.md PR #599 (refs #536, @seo-rii) commit 단위 cherry-pick 9 commits + 메인테이너 5개 후속 정정 (한글 fallback / font-path / char-fallback / VLM 옵션 / export-png CLI + 매뉴얼) + 결정적 검증 + WASM 4,581,465 bytes + 광범위 페이지네이션 sweep (164 fixture / 1,614 페이지 / 회귀 0) + VLM 옵션 게이트웨이 + 시각 판정 ★ 통과 - 검토 보고서 archives 이동: mydocs/pr/pr_599_review.md → mydocs/pr/archives/pr_599_review.md - 5/5 orders 갱신: PR #599 항목 추가 - 컨트리뷰터에게 한글 댓글 추가 등록 (작업지시자 안내 정합) - 후속 이슈 #613 (VLM 프리셋 확장) / #614 (DPI 메타데이터) 등록 완료
…드 실패 정정) PR #599 후속 정정 commit (876d820) 으로 추가된 examples/pr599_png_gateway.rs 가 DocumentCore::render_page_png_native API 사용. 이 API 는 #[cfg(all(not(target_arch = "wasm32"), feature = "native-skia"))] 가드 안에 있어 기본 빌드 (native-skia 미활성) 에서는 메서드가 존재하지 않음. CI 의 cargo build --examples (기본 features) 가 본 example 빌드 시도 → "no method named render_page_png_native" 컴파일 에러 → CI fail. 해결: Cargo.toml 에 [[example]] 정의 추가 + required-features = ["native-skia"] 명시. 기본 빌드는 본 example 자동 skip. 검증: - cargo build --release --examples (기본 features): 통과 (example skip) - cargo build --release --examples --features native-skia: 통과 (example 빌드) - cargo test --lib --release 1134 passed (회귀 0)
PR #600 (closes #513, @oksure Hyunwoo Park) 1차 검토: - 본질 결함: Task #509 의 map_pua_bullet_char 매핑이 convert_pua_enclosed_numbers (composer) 의 CharOverlap 변환에 막혀 도달 못 함 - 본질 정정: composer.rs 에서 F02B1~F02C4 CharOverlap 제외 + paragraph_layout.rs 에 ⑩~⑳ 매핑 추가 (전체 20자 완성) - Copilot review 3개 응답 (aafe85a): ⑩~⑳ 테스트 + 주석 + 폭 계산 정합 - PR base skew (PR #571/#599 패턴) — UI MERGEABLE 표시지만 PR base diff 가 본 사이클 cherry-pick 모두 revert - 그러나 본질 commit 영역이 본 사이클 처리분과 0 중첩 (PR #592 의 SPUA-A 저영역 F0000~F00CF 와 다른 코드포인트 영역) → commit 단위 cherry-pick 가능 - 본 환경 임시 검증: 2 commits cherry-pick 충돌 0 + cargo test --lib --release 1134 passed (회귀 0) + clippy 0건 + PUA 테스트 12 passed 권장 처리: 옵션 A — commit 단위 cherry-pick (2 commits, 단순 머지 절대 금지) + 결정적 검증 + 광범위 sweep + 작업지시자 시각 판정.
…A SVG 출력 정정 — @oksure 2 commits + 시각 판정 ★ 통과) PR #600 (closes #513, @oksure Hyunwoo Park): - 본질 결함: Task #509 의 map_pua_bullet_char 매핑이 convert_pua_enclosed_numbers (composer) 의 CharOverlap 변환에 막혀 도달 못 함 - 본질 정정: composer.rs 에서 F02B1~F02C4 CharOverlap 제외 + paragraph_layout.rs 에 ⑩~⑳ 매핑 추가 (전체 20자 완성) - Copilot review 3개 응답 (aafe85a): ⑩~⑳ 테스트 + 주석 + 폭 계산 정합 PR base skew (PR #571/#599 패턴) — UI MERGEABLE 표시지만 PR base diff 가 본 사이클 cherry-pick 모두 revert. 그러나 본질 commit 영역이 본 사이클 처리분과 0 중첩 (PR #592 의 SPUA-A 저영역 F0000~F00CF 와 다른 코드포인트 영역 F02B1~F02C4) → commit 단위 cherry-pick 가능. cherry-pick 2 commits (충돌 0, author Hyunwoo Park 보존): - 34f8547 fix: Supplementary PUA-A (U+F02B1~F02C4) SVG 출력 정정 - 14f30e8 address review: ⑩~⑳ 테스트 추가 + 주석 갱신 + 폭 계산 정합 검증: - cargo test --lib --release 1134 passed (회귀 0) - cargo test --lib pua 12 passed (supplementary_pua_a_maps_circled_digits ⑩~⑳ GREEN) - svg_snapshot 6/6 / issue_546 1 / issue_554 12 / clippy 0 / build --release - 광범위 페이지네이션 sweep: 164 fixture / 1,614 페이지 / 회귀 0 - SVG 정량 (원문자 출현): pua-test 0→9 / mel-001 20→34 / kps-ai 32→34 / KTX 변경 없음 (PR 본문 100% 재현) 시각 판정 ★ 통과. 별개 영역 발견: pua-test U+F53A 옛한글 자모 시퀀스의 아래아 (U+119E ᆞ) 글리프 미렌더 — 별도 이슈 #615 등록 (옛한글 폰트 fallback 영역). closes #513.
버전 동기화 (4 패키지 모두 0.7.10): - Cargo.toml: 0.7.9 → 0.7.10 - rhwp-vscode/package.json: 0.7.9 → 0.7.10 - npm/editor/package.json: 0.7.9 → 0.7.10 - rhwp-studio/package.json: 0.7.9 → 0.7.10 CHANGELOG (한/영) 신규 항목 [0.7.10] — 2026-05-06: - v0.7.9 후속 patch 사이클 - 외부 기여자 7명 (PR 13건 cherry-pick) — @planet6897/Jaeook Ryu / @oksure / @seo-rii / @cskwork / @johndoekim / @nameofSEOKWONHONG / @jangster77 - 신규 기능: CLI 바이너리 릴리즈 (Issue #608/#612, @almet 요청) + PNG raster backend (PR #599, @seo-rii) + AI 파이프라인 / VLM 연동 도입 - 메인테이너 정정: Skia 폰트 영역 5개 (한글 fallback / font-path / char-fallback / VLM 옵션 / export-png CLI) - 인프라: CI 빌드 안정성 + 광범위 페이지네이션 회귀 sweep (164/1,614) - 후속 이슈 4건 + 잔여 PR 5건 (v0.7.11 후속 patch 영역) 자기검열 통과 (한컴 비교 / 최상급 / 공공기관 오인 표현 0).
v0.7.9 후속 patch 사이클 (5/4 ~ 5/6). ## 신규 기능 - **CLI 바이너리 릴리즈** (Issue #608/#612, @almet 의 요청) - 4 플랫폼 GitHub Release 자산 첨부 (Linux x86_64 / macOS x86_64+aarch64 / Windows x86_64) + SHA-256 체크섬 - **PNG raster backend** (PR #599, @seo-rii) — render P4 단계 - native Skia 기반 PageLayerTree → PNG export, native-skia feature gate - **AI 파이프라인 + VLM 연동 도입** (메인테이너 후속 정정): - --vlm-target claude (1568 longest edge / 1.15 MP, Claude Vision 정합) - --scale / --max-dimension (자동 scale 계산) - export-png CLI 명령 + 매뉴얼 (한글 + 영문 dual) - 한글 폰트 fallback chain + char 단위 fallback (공백 두부 정정) + --font-path 동적 로딩 ## 외부 PR cherry-pick (13 PR / 7 컨트리뷰터) - @planet6897 / Jaeook Ryu (협업): PR #587/#589/#561/#564/#570/#575/ #580/#584/#592/#593/#567 - @oksure (Hyunwoo Park): PR #600 (closes #513) - @seo-rii: PR #599 (refs #536) - @cskwork / @johndoekim / @nameofSEOKWONHONG / @jangster77 — 사이클 누적 ## 메인테이너 정정 Skia 폰트 영역 5개 정정 (한글 fallback / font-path / char-fallback / VLM 옵션 / export-png CLI). ## 인프라 - CI 빌드 안정성 (Cargo.toml [[example]] required-features) - 광범위 페이지네이션 회귀 sweep 도구 (164 fixture / 1,614 페이지 자동) ## 후속 이슈 - #613 (VLM 프리셋 확장) - #614 (DPI 메타데이터) - #615 (pua_oldhangul.rs U+F53A 한컴 정합) - #598 (rhwp-studio 각주 삭제, 외부 컨트리뷰터 공개) ## 잔여 PR (v0.7.11 후속 patch) PR #601, #602 (@oksure) / PR #607 (@dicebattle) / PR #609 (@jangster77, Task #604) / PR #611 (@kihyunnn). 상세: CHANGELOG.md (한글) / CHANGELOG_EN.md (영문).
PR #626 (Follow-up to #599, P5 단계 native Skia equation replay) 처리 완료 후속 영역: - mydocs/pr/archives/pr_626_review.md (1차 검토 + 옵션 분석 + cherry-pick simulation) - mydocs/pr/archives/pr_626_report.md (처리 결과 + native-skia 검증 + PNG 시각 판정 통과) - mydocs/orders/20260507.md PR #626 entry 추가 처리 결과 요약: - 옵션 A: 3 commits 단계별 cherry-pick (author seorii 보존) - devel commits: 067a18b (본질 +717 LOC equation_conv.rs) + dac1caa (docs P5) + 2f6918a (atop fix) - cargo test --lib (default) 1155 / cargo test --features native-skia skia --lib 22 (수식 replay 신규 테스트 포함) - clippy default + native-skia 0 / WASM 4,578,641 bytes (native-skia 영역 외) - 메인테이너 PNG 시각 판정 ★ 통과 (samples/exam_math.hwp 20 페이지 1.5MB) - PR #626 close + 한글 댓글 (연결 이슈 부재 — Follow-up to #599) 본 PR 의 정체성: - opt-in feature 영역 (native-skia) — 기본 빌드 영역 영향 부재 - PR #599 의 follow-up — P4 → P5 단계 진행 - DTP 엔진 (project_dtp_identity) native PNG 렌더링 영역 본질 영역 강화 본 사이클 (5/7) PR 처리 누적: 11건
본질: PR #599 (P4 PNG raster backend) + PR #626 (P5 equation replay) 후속의 P6 단계. native Skia 경로 영역 의 RawSvg leaf 영역 placeholder fallback 영역 → 실제 raster (resvg + tiny-skia 영역) 정합. 기존 (renderer.rs:763): PaintOp::RawSvg { bbox, .. } => draw_placeholder(*bbox, "svg") 정정: rasterize_svg_fragment_to_png + draw_image_bytes 영역 재사용 영역. 신규 함수 (image_conv.rs +82 LOC): - draw_svg_fragment(canvas, fragment, x, y, w, h, sampling) -> bool - rasterize_svg_fragment_to_png(fragment, w, h) -> Option<Vec<u8>> - svg_parse_options() -> usvg::Options<'static> renderer.rs:760+ (line +88/-6): - PaintOp::RawSvg { bbox, raw } 영역 의 draw_svg_fragment 호출 - invalid SVG 영역 fallback placeholder 영역 보존 보안 가드 (영향 좁힘): - MAX_SVG_FRAGMENT_BYTES = 4 MB (fragment 크기 가드) - MAX_SVG_RASTER_PIXELS = 67M (8192x8192 영역 raster 가드) - resolve_string = Box::new(|_, _| None) (external href 차단 — file:// / http:// / https:// 등) - resolve_data = usvg 기본 data: URI resolver (data: URI 만 허용) - resources_dir = None (디렉터리 자동 탐색 차단) - Wrapper SVG: <svg xmlns="..." width="..." height="..." viewBox="...">{fragment}</svg> 의존성 (Cargo.toml): - native-skia feature 영역 의 dep:resvg 추가 - resvg = { version = "0.45", optional = true } 회귀 가드 테스트 (2건 신규): - renders_raw_svg_fragment_as_colored_ink: green rect 100+ green 픽셀 검증 - raw_svg_replay_does_not_load_external_file_hrefs: 외부 file href 영역 red 0 픽셀 검증 (보안 가드 작동 입증) 영향 범위: - native Skia PNG/VLM 경로 영역 의 차트/OLE/내장 SVG 영역 fragment 영역 실제 렌더링 - WASM/browser SVG / CanvasKit / form replay 영역 무영향 (별건) - 다른 PaintOp 영역 (Image, Equation, Path, Text 등) 무영향 비목표 명시 (PR 본문): - browser/WASM SVG replay / CanvasKit raw SVG replay - full SVG security policy 설계 - network/file resource loading - animated SVG / SVG filter 전체 parity - form native replay / VLM preset 확장 (#613) - PNG DPI metadata (#614) 검증: - cargo test --release: lib 1173 + 통합 ALL GREEN, failed 0 - cargo test --release --features native-skia skia --lib: 24/24 PASS (신규 2건 회귀 가드 + 기존 22건) - cargo clippy --release --features native-skia --lib -- -D warnings: 통과 - 광범위 sweep 7 fixture / 170 페이지 / 회귀 0 (Skia 영역 무관 영역, native-skia 미사용 영역 sweep 정합 확정) @seo-rii 7번째 사이클 PR (Skia 영역 트래킹 #536 영역 의 단계적 진전 영역). PR #165 (skia 도입) → #419 (PageLayerTree) → #456 (Canvas 라우팅) → #498 (visual diff) → #599 (P4 PNG) → #626 (P5 equation) → #720 (P6 raw SVG). refs #536 Co-Authored-By: seorii <me@seorii.page> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #740 (@oksure) 옵션 A 처리 — 4 commits cherry-pick + 자기 정정 + no-ff merge. 본질 정정 (1 file, +245/-2): - src/renderer/skia/renderer.rs (+245/-2): · 양식 개체 5종 정적 드로잉 (placeholder 영역 영역 실제 외형 변환) - PushButton: 둥근 사각형(RRect) + 중앙 캡션 - CheckBox: 사각 체크박스 + 체크마크(V자) + 캡션 - RadioButton: 원형 테두리 + 내부 점 + 캡션 - ComboBox: 입력 필드 + 드롭다운 화살표 + 텍스트 - Edit: 입력 필드 + 텍스트 · CSS #rrggbb → Skia Color 변환 utility (parse_css_color) · CJK fallback chain (맑은 고딕/나눔고딕/AppleGothic → custom_typefaces → font_mgr → legacy) · glyph 크기 bbox 비례 자동 조정 (8~14px) 원본 commits (4건): - 58b839a Task #536 P7: native Skia form control static replay - 2889d9f Copilot 리뷰 반영: RRect import + bg_color 일관 + ComboBox/Edit text-only - a8093f2 CI 수정: Path::new() → PathBuilder (native-skia 호환) - 3b5a027 fix: form control 텍스트 렌더링 CJK fallback 적용 본 환경 자기 정정 (commit `4be49daa`): - impl SkiaLayerRenderer (line 793) 닫힘 brace 누락 발견 — CI Build & Test job 75178101688 (native-skia tests) 동일 결함 발생 - 4번째 commit 85c05bc (CJK fallback) 에서 standalone fn → method 변환 시 impl 닫힘 brace 누락 - 자기 정정 1줄 추가 (line 1025) 자기 검증: - cherry-pick 충돌 0건 (auto-merge 정합) - cargo build --release --features native-skia ✅ 통과 (자기 정정 후) - cargo test --release --features native-skia --lib skia ✅ 24/24 PASS - rhwp export-png samples/form-01.hwp ✅ form-01.png 13353 bytes 생성 - 작업지시자 SVG 시각 판정 ✅ 통과 PR supersede 체인: - PR #599 (P4) → PR #626 (P5) → PR #720 (P6) → PR #740 (P7) — Issue #536 단계적 진전 - 동일 컨트리뷰터 @oksure (PR #599/#626/#720 영역 영역 P4-P6) → @oksure (P7) 영역 영역 정합 Part of #536
P9 단계 — native Skia text replay 영역 기존 TextRunNode payload 영역 더 많이 소비. 단순 glyph drawing 영역 layer payload 의 text metadata 영역 가능 범위 영역 replay. Skia native raster 트래킹 (Issue #536) 의 단계적 진전: - P4 #599 → P5 #626 → P6 #720 → P8 #761 → P9 #769 P9 본질 보강: - char overlap / tab leader / text decoration (underline/strike/overline) - shade/shadow/outline-style effect - emphasis dot (한글 강조점) - vertical rotation (세로쓰기) - output options 영역 control mark replay 인프라 도입 — text_replay.rs 모듈 분리 (P10 → P9 통합): - src/renderer/skia/text_replay.rs 신규 (+748) - renderer.rs 영역 page/layer replay orchestration 영역 집중 - src/renderer/skia/mod.rs 모듈 등록 본 환경 cherry-pick: - 49b540a (P8) → empty (PR #761 머지 완료 영역 동일 본질) → skip - 8f079b1 (P9 본질 1) → cherry-pick - c74fb92 (P9 본질 2, split) → cherry-pick Non-goals (PR 본문 명시): - full text source table / glyph-run IR 미포함 - Skia 영역 기본 public render path 전환 부재 - targeted raster test 외 visual/pixel regression infrastructure 추가 부재 검증: - cargo build/test/clippy --release ALL GREEN - cargo test --features native-skia --lib skia → 28/28 PASS (신규 4건 + 기존 24건) - renders_char_overlap_text_run_as_ink - renders_decorated_text_as_ink - renders_tab_leader_for_empty_text_run - renders_output_control_marks_as_ink - cargo clippy --release --features native-skia --lib -- -D warnings 통과 - 광범위 sweep 7 fixture / 170 페이지 / 회귀 0 (skia 만 영역 svg sweep 무영향 입증) - 시각 판정 면제 (작업지시자 결정 — targeted raster + sweep 통과 + Skia 만 변경) Refs #536
…ract (P11) P11 단계 — P9 영역 영역 text replay parity 후속 영역 영역 Text IR v2 compatibility contract 추가. Skia native raster Issue #536 트래킹 단계적 진전: P4 #599 → P5 #626 → P6 #720 → P8 #761 → P9 #769 → P11 #797 중요: 본 PR 은 GlyphRun 을 기본 경로로 만드는 PR 이 아니라 TextRun v2 compatibility contract 를 완성하는 PR. 4 본질 원칙: - Compatibility first — 모든 backend 가 TextRun fallback 으로 렌더링 가능 - Additive schema — schemaMinorVersion + feature negotiation (기존 consumer 미파괴) - Source traceability — text_sources + TextRun.source span - Placement/cluster metadata — paintStyle/projectionKind/orientation/placement/clusterBasis/clusters/legacyVisuals 신규 인프라: - PaintOp::{CharOverlap, TextControlMark, TabLeader, TextDecoration} — explicit visual ops - PageLayerTree.text_sources + TextSourceTable (export-local) - TextRun.source span + 7 신규 metadata - schemaMinorVersion + resourceTableMinorVersion + feature negotiation - docs/text-ir-v2.md migration contract Renderer 정정 — 4 backend 동기 (feedback_image_renderer_paths_separate 권위 사례): - svg_layer.rs / canvas.rs / skia/renderer.rs / web_canvas.rs — 신규 special visual op skip (double-painting 방지) Non-goals (Still designing): - GlyphRun eligibility / font resource table / cluster basis / fallback diagnostics — P12+ 분리 검증: - cargo build/test/clippy --release ALL GREEN (clippy -D warnings) - native-skia 28/28 PASS (PR #769 인프라 보존) - 광범위 sweep 7 fixture / 170 페이지 / 회귀 0 (Compatibility first 원칙 입증) - 시각 판정 면제 (작업지시자 결정 — contract 정합 단계 + 결정적 검증 + sweep 통과) Refs #536
…p 활성화 @oksure — Issue #790 (외부 제안): Cargo.toml [profile.release] 영역 LTO + codegen-units=1 + strip 활성화 영역 바이너리 크기 축소 + 런타임 성능 개선. 본질 (2 commits, Cargo.toml +5/-0): - lto = true (Fat LTO, 크로스 크레이트 인라이닝 최적화) - codegen-units = 1 (단일 코드젠 유닛, 전역 최적화 극대화) - strip = "debuginfo" (디버그 정보 제거, panic backtrace symbol table 보존) - 리뷰 반영 commit (9ccb0c3): strip = true → strip = "debuginfo" 정정 본 환경 충돌 수동 해결 (Cargo.toml): - devel 측 — PR #599 example pr599_png_gateway (native-skia required) - PR 측 — [profile.release] 영역 5 라인 추가 - 양측 모두 보존 (PR #599 example + [profile.release] 정합) 본 환경 정량 측정: | 항목 | before | after | 차이 | |------|--------|-------|------| | rhwp CLI 크기 | 14 MB | 10 MB | -4 MB (-28%) | | WASM 크기 | 4.6 MB | 4.3 MB | -0.3 MB (-6.5%) | | cargo build --release (clean) | ~58s | 2m 53s | +1m 55s (~3배) | | WASM 빌드 (Docker) | ~1m 30s | 2m 23s | +53s (+59%) | | cargo test | ALL GREEN | ALL GREEN | 회귀 0 | | cargo clippy -D warnings | 통과 | 통과 | 회귀 0 | | sweep 7 fixture / 170 페이지 | baseline | 170 same / 0 diff | byte-identical | → 빌드 시간 ~3배 증가 영역 release 빌드 한정 (개발 빌드 영향 부재). sweep byte-identical 영역 SVG 출력 무영향 입증.
변경 요약
이번 PR은 render P4 단계로,
PageLayerTree를 native Skia로 replay해서 PNG를 만들 수 있는 첫 raster backend를 추가합니다.P1에서
PageLayerTree경계를 만들고, P2/P3에서 Canvas layer path와 diff 테스트를 붙였고, 이번에는 그 IR을 native backend에서도 실제로 replay할 수 있는지 확인하는 단계입니다.주요 변경은 아래와 같습니다.
LayerRasterRenderer,RasterRenderOptions,RasterRenderOutput추가native-skiafeature 추가SkiaLayerRenderer추가DocumentCore::render_page_png_native(page)추가PageLayerTree기반 PNG encode 경로 추가이 PR의 Skia 경로는 아직 완성형 renderer라기보다는
PageLayerTree가 native raster backend까지 갈 수 있는지 검증하는 초기 backend입니다. 그래서 기본 SVG/Canvas 출력은 그대로 두고, native feature를 켰을 때만 PNG export API를 사용할 수 있게 했습니다.관련 이슈
refs #536
범위
이번 PR에 포함한 범위는 아래 정도입니다.
PageLayerTreereplay 기반 raster outputnative-skia비목표
아래는 일부러 이번 PR에 넣지 않았습니다.
특히 equation/raw-svg/form은 이번 PR에서는 placeholder/fallback replay 수준입니다. 실제 native replay는 후속 PR에서 따로 보는 게 맞습니다.
테스트
git diff --check upstream/devel...origin/render-p4cargo testcargo clippy -- -D warningscargo check --target wasm32-unknown-unknown --libcargo test --features native-skia skia --libSVG 샘플 내보내기와 웹 렌더링 확인은 이번 PR의 직접 범위가 아닙니다. P4는 native-only Skia PNG backend 추가이고, wasm 쪽은
cargo check --target wasm32-unknown-unknown --lib로 native Skia 의존성이 새지 않는지만 확인했습니다.스크린샷
없음.
이번 PR은 UI 변경이 아니라 native PNG raster backend 추가입니다. 대신 Skia 테스트에서 PNG decode, pixel sampling, clip, image crop/tile/effect, placeholder fallback, raster option guard를 확인합니다.