Skia form control static replay (P7)#740
Conversation
- PushButton: 둥근 사각형 + 중앙 정렬 캡션 - CheckBox: 체크박스 + 체크마크(value≠0) + 캡션 - RadioButton: 원형 + 내부 점(value≠0) + 캡션 - ComboBox: 입력 필드 + 드롭다운 화살표 삼각형 + 텍스트 - Edit: 입력 필드 + 텍스트 - CSS 색상 (#rrggbb) 파싱 → Skia Color 변환 - 기존 draw_placeholder 호출을 form_type별 정적 드로잉으로 교체 Part of edwardkim#536
There was a problem hiding this comment.
Pull request overview
Native Skia PNG backend에서 FormObject가 placeholder로만 보이던 동작을 개선해, 5종 양식 개체를 실제 외형으로 정적 드로잉(replay)하도록 변경하는 PR입니다.
Changes:
PaintOp::FormObject처리 경로를draw_placeholder()에서draw_form_control()로 교체- PushButton/CheckBox/RadioButton/ComboBox/Edit 정적 드로잉 로직 추가
- CSS
#rrggbb→ SkiaColor변환 유틸(parse_css_color) 추가
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let rrect = RRect::new_rect_xy(rect, 3.0, 3.0); | ||
| canvas.draw_rrect(rrect, &fill); |
| fn draw_form_control( | ||
| canvas: &Canvas, | ||
| bbox: crate::renderer::render_tree::BoundingBox, | ||
| form: &crate::renderer::render_tree::FormObjectNode, | ||
| ) { |
| let bg_color = parse_css_color(&form.back_color).unwrap_or(Color::from_rgb(240, 240, 240)); | ||
| let fg_color = parse_css_color(&form.fore_color).unwrap_or(Color::from_rgb(0, 0, 0)); | ||
| let border_color = Color::from_rgb(160, 160, 160); |
| let display = if form.text.is_empty() { &form.caption } else { &form.text }; | ||
| if !display.is_empty() { |
| let display = if form.text.is_empty() { &form.caption } else { &form.text }; | ||
| if !display.is_empty() { |
| PaintOp::FormObject { bbox, form } => { | ||
| draw_placeholder(*bbox, form.caption.as_str()); | ||
| draw_form_control(canvas, *bbox, form); | ||
| } |
|
|
||
| let label = if form.caption.is_empty() { &form.name } else { &form.caption }; | ||
| if !label.is_empty() { | ||
| let mut font = Font::default(); |
There was a problem hiding this comment.
여기서 Font::default()로 바로 그리면 #599에서 들어간 with_font_paths / 한글 fallback / custom typeface 경로를 타지 못할 것 같습니다. form caption/text에는 한글이 들어갈 가능성이 높아서, native PNG에서 tofu나 누락 glyph가 나올 수 있습니다. 가능하면 draw_form_control이 font_mgr를 받거나, 기존 Skia text/font helper를 통해 동일한 fallback 경로를 재사용하면 좋겠습니다.
| } | ||
| PaintOp::FormObject { bbox, form } => { | ||
| draw_placeholder(*bbox, form.caption.as_str()); | ||
| draw_form_control(canvas, *bbox, form); |
There was a problem hiding this comment.
P7 범위와 구현 방향은 좋아 보입니다. 다만 이 변경으로 FormObject가 placeholder가 아니라 실제 native replay 경로를 타게 되므로, 5종 form control(PushButton/CheckBox/RadioButton/ComboBox/Edit)을 한 tree에 넣고 ink/checked mark/text 정도를 확인하는 native-skia smoke test가 같이 있으면 이후 회귀를 잡기 더 안전할 것 같습니다.
draw_form_control을 SkiaLayerRenderer 메서드로 변환하여 font_mgr를 통한 한글 폰트 fallback chain 사용. - make_form_font(): CJK 폰트 후보 (맑은 고딕, 나눔고딕 등) → custom_typefaces → font_mgr → legacy fallback 순서로 탐색 - Font::default() 5개소 → self.make_form_font() 대체 - PushButton/CheckBox/RadioButton caption + ComboBox/Edit text 모두 동일 fallback chain 적용 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
리뷰 피드백 반영 (3b5a027): CJK 폰트 fallback 적용 (@seo-rii, Copilot 공통):
기타 Copilot 지적 사항 확인:
smoke test: native-skia feature 빌드가 CI에서 실행되지 않아 통합 테스트 추가가 어려운 상황입니다. 로컬에서 form control 포함 HWP 파일로 PNG 출력 확인은 가능합니다만, CI 자동화 테스트는 별도 논의가 필요할 것 같습니다. |
| } | ||
| } | ||
|
|
||
| fn parse_css_color(s: &str) -> Option<Color> { |
There was a problem hiding this comment.
여기서 draw_form_control 함수는 닫혔지만, 위에서 새로 연 impl SkiaLayerRenderer 블록이 아직 닫히지 않은 상태로 보입니다. 그래서 아래 parse_css_color/mod tests가 impl 내부로 들어가면서 native CI가 unclosed delimiter로 실패합니다. fn parse_css_color 앞에 }를 하나 더 추가해 impl 블록을 닫아야 할 것 같습니다.
cherry-pick 의 commits 누적 변경에서 impl SkiaLayerRenderer (line 793)의 닫힘 brace 부재 — line 1025 의 } 는 fn draw_form_control 닫힘만 처리. CI 의 Build & Test job 75178101688 에서 동일 결함 발생 (PR FAILURE 상태). native-skia 빌드 검증: - cargo build --release --features native-skia ✅ 통과 - cargo test --release --features native-skia --lib skia ✅ 24/24 PASS
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
- mydocs/pr/archives/pr_740_report.md: 처리 보고서 작성 · native Skia form control static replay (P7) — Part of #536 · 양식 개체 5종 정적 드로잉 (PushButton/CheckBox/RadioButton/ComboBox/Edit) · 본 환경 자기 정정 — impl SkiaLayerRenderer 닫힘 brace 누락 (CI Build & Test 동일 결함 재현) · native-skia 24/24 PASS + form-01.png 생성 + 작업지시자 SVG 시각 판정 통과 · PR supersede 체인 — Issue #536 P4 → P5 → P6 → P7 권위 사례 강화 - mydocs/orders/20260510.md: PR #740 항목 추가 (5/10 사이클 영역 영역 13건 처리)
|
@oksure 님, 검토 + 머지 완료했습니다. 처리 결과옵션 A (4 commits cherry-pick + 자기 정정 + no-ff merge `db76b8dd`) 로 처리. 자기 정정 (commit `4be49daa`)CI 의 Build & Test job (`75178101688`) 영역 영역 native-skia tests 실패 (FAILURE) 재현 — 4번째 commit `85c05bcd` (CJK fallback) 영역 영역 standalone `fn draw_form_control` → `impl SkiaLayerRenderer { ... }` 의 method 변환 시 impl 닫힘 brace 누락 (line 1025). 본 환경 영역 영역 1줄 추가 정정. 자기 검증
작업지시자 SVG 시각 판정 ✅ 통과양식 개체 5종 (PushButton/CheckBox/RadioButton/ComboBox/Edit) 외형 정합 + CJK fallback chain (맑은 고딕/나눔고딕 등) 정합. PR supersede 체인 — Issue #536 단계적 진전 권위 사례 강화
`feedback_pr_supersede_chain` 정합 — Issue #536 단계적 진전 + 컨트리뷰터 전환 (@seo-rii P4-P6 → @oksure P7). 처리 보고서: `mydocs/pr/archives/pr_740_report.md`. @oksure 님 20+ 사이클 컨트리뷰션 영역 — 5/10 사이클 영역 영역 PR #720/#723/#725/#728/#729/#730/#732/#734/#735/#737/#738/#739/#740 영역 13건 처리 완료 영역. |
PR #752 의 performDelete 가 this.deleteObjectControl(ref) 호출 → ref.type 영역 영역 'line' 가능 (getSelectedPictureRef 시그니처) 영역 영역 래퍼 시그니처 영역 영역 'image|shape|equation|group' 만 정의 영역 영역 tsc 오류 발생. input-handler-picture.ts 의 실제 구현 영역 영역 이미 'line' 포함 영역 영역, input-handler.ts 의 래퍼 3개 (getObjectProperties / setObjectProperties / deleteObjectControl) 영역 영역 'line' 추가 영역 영역 정합. devel HEAD 영역 영역 잠재 결함 (PR #752 와 무관, performDelete 신규 호출 영역 영역 노출됨) — PR #740 자기 정정 패턴 정합.
PR #786 영역 chordMapN['m'] / ['ㅡ'] 매핑 정정 영역 영역 chord 2번째 키 영역만 처리. 그러나 chord 1번째 키 (Ctrl+N) 영역 영역 InputHandler textarea keydown listener 영역 영역만 차단 — textarea 미포커스 상태 (메뉴 바 / button 클릭 후 등) 영역 영역 keydown 영역 document 발동 영역 setupGlobalShortcuts 영역 영역 InputHandler.active 영역 영역 return → Ctrl+N 차단 부재 → 크롬 새 창 발동. 정정: setupGlobalShortcuts 영역 영역 InputHandler 활성 시점 영역 영역도 Ctrl+N 차단 추가: - e.preventDefault() (크롬 새 창 차단) - inputHandler._pendingChordN = true (chord 1번째 키 활성화) - inputHandler.focus() (textarea 포커스 복귀 — 후속 키 영역 InputHandler chord 2번째 키 처리) 작업지시자 시각 검증 영역 영역 발견: "수식 객체 삭제 통과. Ctrl+N 누르면 크롬 웹브라우저 단축키가 먼저 발동." PR #740 자기 정정 패턴 정합 — devel HEAD 잠재 결함 영역 영역 본 PR 의 신규 호출 영역 영역 노출 영역 자기 정정 commit.
…cut 회피) PR #786 영역 chordMapN['m'] / ['ㅡ'] 매핑 정정 영역 영역 chord 2번째 키 영역만 처리. 그러나 Chrome / Edge 영역 영역 Ctrl+N (새 창) 영역 영역 OS-level reserved shortcut 영역 영역 JS preventDefault() 차단 불가 영역 영역 chord 1번째 키 영역 영역 자체 발동 부재. 작업지시자 결정: chord 키 영역 영역 Ctrl+N → Ctrl+M 변경. 정정 영역: - input-handler-keyboard.ts: chordMapN → chordMapM, _pendingChordN → _pendingChordM, chord 1번째 키 영역 영역 'm'/'M'/'ㅡ' (Ctrl+M) - insert.ts: shortcutLabel 'Ctrl+N,M' → 'Ctrl+M,M' (수식) - table.ts: shortcutLabel 'Ctrl+N,F' → 'Ctrl+M,F' (계산식) - edit.ts: shortcutLabel 'Ctrl+N,K' → 'Ctrl+M,K' (누름틀 고치기) - page.ts: shortcutLabel 'Ctrl+N,S' → 'Ctrl+M,S' (감추기) 자기 정정 commit (7bc2dc0, setupGlobalShortcuts Ctrl+N chord 시작 보강) revert 영역 영역 fb1a22c 머지 — 효과 없는 정정 영역 영역 정합성 영역 영역 보존. 작업지시자 시각 검증 영역 영역 발견 (PR #786 후속): "Ctrl+N 누르면 크롬 웹브라우저 단축키가 먼저 발동." 본질: Chrome reserved shortcut 영역 영역 JS 차단 불가 영역 영역 chord 키 변경 영역 영역 회피. PR #740 자기 정정 패턴 정합.
작업지시자 시각 검증 영역 영역 발견: '한글 IME 상태에서도 적용되어야 합니다.' 본질: 한국어 IME 합성 중 영역 영역 e.key === 'Process' (Chrome 영역 영역 IME 합성 중 영역 영역 일관 영역 영역) 영역 영역 line 201 영역 영역 IME 합성 중 영역 영역 즉시 return → chord 1번째/2번째 키 활성화 부재. 정정 (input-handler-keyboard.ts +18): - chord 1번째 키 영역 영역 IME 합성 중 영역 영역 e.code === 'KeyM' 영역 영역 활성화 - chord 2번째 키 영역 영역 _pendingChordM 활성화 시 e.code 영역 영역 chordMapM lookup (KeyM/KeyN/KeyS/KeyF/KeyK → 'm'/'n'/'s'/'f'/'k') 본 환경 영역 영역 IME 합성 중 영역 영역 chord 1/2번째 키 영역 영역 모두 e.code 영역 영역 판별 영역 영역 한글 IME 상태 영역 영역 정합 동작. PR #740 자기 정정 패턴 정합.
작업지시자 시각 검증 영역 발견: 'Alt+Delete 만 동작하지 않습니다.' 본질: shortcut-map.ts:97 영역 영역 Alt+Delete → table:delete-col 매핑 (5/10 이전 등록) 영역 영역 일반 편집 영역 영역 dispatcher.dispatch 영역 영역 silently fail (canExecute=inTable 차단) + return → switch (e.key) case 'Delete' 영역 영역 도달 부재 → 단어 삭제 미동작. 정정: Alt 조합 단축키 가드 영역 영역 Alt+Delete 영역 영역 표 안/외 분기 추가: - 표 안 + Alt+Delete: table:delete-col (칸 지우기, 기존 동작 보존) - 표 외 + Alt+Delete: 다음 단어 삭제 (PR #794 본질) - Alt+Backspace: 이전 단어 삭제 (항상) - Alt+Arrow: 단어 이동 (항상) PR #740 자기 정정 패턴 정합.
변경 사항
native Skia 렌더러에서 양식 개체(form control)를 placeholder 대신 실제 외형으로 정적 드로잉합니다.
구현된 양식 개체 5종
기술 사항
FormObjectNode의form_type,caption,text,value,fore_color,back_color활용#rrggbb색상 → SkiaColor변환 유틸리티 추가draw_placeholder()호출을draw_form_control()로 교체P6 의존성 참고
테스트
cargo test: 전체 통과cargo clippy -- -D warnings: 경고 없음Part of #536
감사합니다.