Skip to content

Commit 843ebcf

Browse files
committed
docs: macOS headless PNG 렌더 hang 업스트림 이슈 초안 추가
1 parent d773a07 commit 843ebcf

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
status: Active
3+
description: "업스트림 제안 — headless macOS (CI 등) 에서 PNG 렌더가 미설치 폰트 fallback 시 CoreText downloadable lookup IPC 로 hang. 시스템 폰트 사전 필터링 patch 로 실측 0.43초 정상화 검증. 상류 등록 보류."
4+
last_updated: 2026-05-11
5+
---
6+
7+
> 외부 binding (`rhwp-python`) 구현 중 업스트림에서 수정이 필요해 보이는 부분을 발견하여, Claude 로 조사 및 다차례 사실 검증을 거친 결과입니다.
8+
9+
## 현상
10+
11+
`SkiaLayerRenderer::render_raster_with_options`**headless macOS** (GHA `macos-latest` 등) 에서 무한 hang. interactive 데스크톱과 SVG export 는 정상이라 **실질 영향은 CI / 빌드팜 한정**입니다.
12+
13+
HWP 본문이 지정한 `한컴*` / `새*` / `함초롬*` 폰트가 시스템에 없을 때 CoreText 가 `fontd` 에 다운로드 가능 여부를 IPC 로 문의 → headless 환경에서는 `launchd``fontd` 를 안 띄워 응답자 부재 → `mach_msg2_trap` 영구 차단 (timeout 도 없음).
14+
15+
생성 시점에 시스템 폰트 family 를 캐시해 missing family 는 `match_family_style` 호출 자체를 skip 하면 해결 (실측 30분 hang → 0.43초).
16+
17+
## 원인
18+
19+
`src/renderer/skia/renderer.rs:286` 부근 fallback chain 루프가 missing family 를 `match_family_style` 에 전달 → CoreText 다운로드 lookup → `fontd` IPC 영구 대기. 첫 family 에서 막혀 chain 후속 family 는 시도조차 안 됨. brew 로 Noto / Nanum 등 chain 폰트 사전 설치도 효과 없음 (실측).
20+
21+
<details>
22+
<summary><code>sample(1)</code> native stack (hang 중)</summary>
23+
24+
```
25+
CTFontDescriptorCreateMatchingFontDescriptor (CoreText)
26+
TDescriptor::CreateMatchingDescriptorInternal
27+
TDescriptorSource::CopyDescriptorsForRequest
28+
libFontRegistry::XTCopyFontsWithProperties
29+
TDownloadableFontManager::Download()
30+
libFontRegistryUI::DownloadFontsForProperties
31+
CFMessagePortSendRequest → mach_msg2_trap ← 영구 차단
32+
```
33+
34+
DispatchQueue `com.apple.FontRegistryUI`, leaf `mach_msg2_trap` — 네트워크가 아니라 로컬 IPC 수신자 부재.
35+
36+
</details>
37+
38+
## 재현
39+
40+
- 환경: GHA `macos-latest` (= `macos-15` 비대화형, ARM64), rhwp pin `62a458aa317e962cd3d0eec6096728c172d57110`
41+
- 호출: `samples/aift.hwp` + `render_raster_with_options(page=0)` → 30분+ hang
42+
- 대조: 같은 runner 의 `rhwp export-svg` 6초 / 개발자 desktop (HWP 폰트 설치) 53ms
43+
44+
trigger = AND(PNG raster path, HWP 명시 폰트 시스템 부재, `fontd` 미기동). macOS 13–16 / 26 모두 동일 조합이면 영향 가능 (직접 검증은 15.7.4).
45+
46+
## 제안 — 시스템 폰트 사전 필터링
47+
48+
```rust
49+
use std::collections::{HashMap, HashSet};
50+
51+
pub struct SkiaLayerRenderer {
52+
font_mgr: FontMgr,
53+
custom_typefaces: HashMap<String, Typeface>,
54+
system_families: HashSet<String>, // ← 추가
55+
}
56+
57+
impl SkiaLayerRenderer {
58+
pub fn new() -> Self {
59+
let font_mgr = FontMgr::default();
60+
let system_families: HashSet<String> = font_mgr.family_names().collect();
61+
Self { font_mgr, custom_typefaces: HashMap::new(), system_families }
62+
}
63+
}
64+
65+
// src/renderer/skia/renderer.rs:286 근처
66+
for family in &families {
67+
if !self.system_families.contains(AsRef::<str>::as_ref(family)) {
68+
continue; // missing family 는 CoreText 호출 회피
69+
}
70+
if let Some(tf) = self.font_mgr.match_family_style(family, font_style) {
71+
push(&mut chain, &mut seen, tf);
72+
}
73+
}
74+
```
75+
76+
`family_names()``CTFontManagerCopyAvailableFontFamilyNames` 호출이라 자체적으로 downloadable lookup 안 함 (실측 hang 해소로 후행 검증). 비고: `CTFontManagerSetAutoActivationSetting(null, kCTFontManagerAutoActivationDisabled)` 도 시도했으나 `libFontRegistryUI` lookup 까지 끄지 못해 같은 hang 실측.
77+
78+
## 검증
79+
80+
| 상태 | 결과 | CI run |
81+
|---|---|---|
82+
| baseline (patch 없음) | 30분 hang | [#25646433838](https://github.com/DanMeon/rhwp-python/actions/runs/25646433838) |
83+
| `SetAutoActivationSetting` 시도 | hang 재현 | [#25649592697](https://github.com/DanMeon/rhwp-python/actions/runs/25649592697) |
84+
| 사전 필터링 적용 | `1 passed in 0.43s` / `592 passed in 51.25s` | [#25650400186](https://github.com/DanMeon/rhwp-python/actions/runs/25650400186) |
85+
86+
SVG path / custom typeface 루프 regression 없음. cost: 생성 시 `family_names()` 1회 (수십 ms), 이후 HashSet O(1). 코드 약 10줄. 실효는 CI / headless 환경의 hang 해소 한 가지 — interactive desktop 은 `fontd` 응답이 빨라 perf 차이 사실상 없음, 다른 OS 도 영향 없음.
87+
88+
## 참고 위치
89+
90+
- `src/renderer/skia/renderer.rs:19-33``SkiaLayerRenderer` 구조체 / `new` (필드 추가, 캐싱 위치)
91+
- `src/renderer/skia/renderer.rs:286` 근처 — fallback chain 루프 (수정 대상)
92+
- `src/renderer/style_resolver.rs:566-583``한컴` / `` / `함초롬` family 매핑 (trigger 원인)

0 commit comments

Comments
 (0)