Task #191: 회전된 도형 리사이즈 커서 개선 및 Flip 처리 추가#192
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
회전된 도형/오브젝트 편집 UX 개선(#191)과 함께, HWPX 저장/검증 인프라 및 렌더링 품질 개선까지 여러 기능이 한 PR에 함께 포함되어 있습니다.
Changes:
- (Studio) 회전된 오브젝트의 핸들/프리뷰 렌더링 및 회전각 반영 리사이즈 커서 처리 추가
- (Core/WASM) HWPX 내보내기(exportHwpx) 및 원본 포맷 조회(getSourceFormat) 지원 추가, 저장 로직이 원본 포맷을 따르도록 수정
- (Renderer/Docs/Tools) 수식 폰트 체인/이미지 효과 필터/탭 측정 정밀화/검증 스크립트 및 다수 문서/샘플 업데이트
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tools/verify_hwpx.py | 한컴(Windows)+pyhwpx 기반 단일 HWPX 자동 검증 스크립트 추가 |
| tools/verify_all.py | stage 산출물들을 일괄 검증하는 래퍼 스크립트 추가 |
| tests/hwpx_roundtrip_integration.rs | HWPX 라운드트립 통합 테스트(스모크 포함) 추가 |
| src/wasm_api.rs | WASM API에 exportHwpx/getSourceFormat 노출 |
| src/serializer/mod.rs | HWPX serializer 노출 및 SerializeError 공용화 |
| src/serializer/hwpx/writer.rs | HWPX ZIP writer 추가(결정적 mtime, mimetype STORED 등) |
| src/serializer/hwpx/utils.rs | quick-xml 기반 유틸(선언/태그/텍스트) 및 escape 헬퍼 추가 |
| src/serializer/hwpx/templates/version.xml | HWPX version.xml 템플릿 추가/갱신 |
| src/serializer/hwpx/templates/settings.xml | HWPX settings.xml 템플릿 추가 |
| src/serializer/hwpx/templates/empty_section0.xml | 빈 section0.xml 템플릿 추가 |
| src/serializer/hwpx/templates/empty_content.hpf | 빈 content.hpf 템플릿 추가 |
| src/serializer/hwpx/static_assets.rs | HWPX 정적 자산 상수 묶음 추가 |
| src/serializer/hwpx/roundtrip.rs | IR diff 기반 HWPX roundtrip 검증 로직 추가 |
| src/serializer/hwpx/fixtures.rs | 템플릿 fixture 상수 및 간단 테스트 추가 |
| src/serializer/hwpx/field.rs | 필드/북마크/각주·미주 뼈대 직렬화 추가 |
| src/serializer/hwpx/content.rs | content.hpf 동적 생성기 추가 |
| src/serializer/cfb_writer.rs | 공용 SerializeError로 통합 |
| src/renderer/svg.rs | 수식 bbox 스케일 보정 + 이미지 효과(SVG filter) 처리 + 수식 폰트 임베딩용 코드포인트 수집 |
| src/renderer/style_resolver.rs | 탭 위치 보정 주석 정리 |
| src/renderer/render_tree.rs | ImageNode에 effect 필드 추가 |
| src/renderer/layout/text_measurement.rs | inline tab 폭 계산 정합성 개선 + 전각 기호 범위 확장 |
| src/renderer/layout/table_cell_content.rs | 표 셀 내 그림 렌더 노드에 effect 전달 |
| src/renderer/layout/shape_layout.rs | 그림 렌더 노드에 effect 전달 |
| src/renderer/layout/picture_footnote.rs | 각주/미주 그림 노드에 effect 전달 |
| src/renderer/layout/paragraph_layout.rs | inline_tabs 전달 + 수식 baseline 정렬 개선 + 그림 effect 전달 |
| src/renderer/equation/svg_render.rs | 수식 SVG <text>에 font-family 체인 적용 및 일부 레이아웃 보정 |
| src/renderer/equation/canvas_render.rs | Canvas 수식 폰트 체인 적용 |
| src/renderer/composer/re_sample_gen.rs | 테스트 생성 샘플 출력 경로를 output/로 이동 및 디렉토리 생성 |
| src/renderer/composer.rs | 수식 TAC 폭 처리 주석/근거 보강 |
| src/model/table.rs | 정렬 로직을 sort_by_key로 단순화(클리피 대응) |
| src/main.rs | export-svg에 --show-grid 옵션 추가 및 SVG 격자 오버레이 삽입 |
| src/error.rs | SerializeError 경로 변경 반영 |
| src/document_core/queries/cursor_nav.rs | sort_by_key로 변경(클리피 대응) |
| src/document_core/mod.rs | source_format(FileFormat) 필드 추가 |
| src/document_core/commands/object_ops.rs | 도형 리사이즈 0 크기 방어(MIN_SHAPE_SIZE clamp) + 회귀 테스트 추가 |
| src/document_core/commands/document.rs | from_bytes에서 원본 포맷 감지 + export_hwpx_native 추가 |
| rhwp-studio/src/styles/responsive.css | 모바일 UI padding 조정 |
| rhwp-studio/src/hwpctl/index.ts | SaveAs가 원본/요청 포맷에 따라 HWP/HWPX로 분기 저장 |
| rhwp-studio/src/engine/table-object-renderer.ts | 회전된 오브젝트 핸들/회전핸들/드래그 프리뷰 렌더링 지원 |
| rhwp-studio/src/engine/input-handler-mouse.ts | 회전각 반영 리사이즈 커서 계산 및 드래그 중 커서 업데이트 |
| rhwp-studio/src/core/wasm-bridge.ts | exportHwpx/getSourceFormat 브리지 추가 |
| rhwp-studio/src/core/font-loader.ts | Latin Modern Math 폰트 로더 목록 추가 |
| rhwp-studio/src/command/commands/file.ts | 저장 시 원본 포맷(HWP/HWPX) 따라 분기 및 picker 타입 반영 |
| rhwp-studio/package-lock.json | rhwp-studio 버전 0.7.2로 갱신 |
| rhwp-chrome/sw/thumbnail-extractor.js | 중복 주석 제거 |
| rhwp-chrome/options.js | 확장 옵션 페이지 스크립트 분리 추가 |
| rhwp-chrome/options.html | 옵션 페이지 인라인 스크립트 제거 후 options.js 로드 |
| rhwp-chrome/dev-tools-inject.js | devtools 주입 버전 문자열 갱신 및 샘플 HTML 수정 |
| rhwp-chrome/content-script.js | 확장 버전 갱신 및 hover thumb 렌더링 정리 |
| rhwp-chrome/build.mjs | 빌드 산출물에 options.js 복사 추가 |
| mydocs/working/task_m100_182_stage4.md | HWPX serializer Stage 4 보고서 추가 |
| mydocs/working/task_m100_182_stage3.md | HWPX serializer Stage 3 보고서 추가 |
| mydocs/working/task_m100_182_stage0.md | HWPX serializer Stage 0 보고서 추가 |
| mydocs/working/task_m100_164_stage2_3.md | #164 Stage 2.3 보고서 추가 |
| mydocs/working/task_m100_164_stage2_2.md | #164 Stage 2.2 보고서 추가 |
| mydocs/working/task_m100_164_stage2_1.md | #164 Stage 2.1 보고서 추가 |
| mydocs/working/task_m100_164_stage1.md | #164 Stage 1 보고서 추가 |
| mydocs/working/task_m100_164_report.md | #164 최종 보고서 추가 |
| mydocs/working/task_m100_142_stage1_v2.md | #142 v2 단계 보고서 추가 |
| mydocs/working/task_m100_142_bugs.md | #142 버그 목록 문서 추가/갱신 |
| mydocs/working/task_m100_141_stage1.md | #141 단계 보고서 추가 |
| mydocs/working/task_m100_141_report.md | #141 최종 보고서 추가 |
| mydocs/working/task_m100_139_stage4.md | #139 단계 보고서 추가 |
| mydocs/working/task_m100_139_stage2.md | #139 단계 보고서 추가 |
| mydocs/working/task_m100_139_stage1.md | #139 단계 보고서 추가 |
| mydocs/troubleshootings/tab_tac_overlap_142_159.md | 탭+TAC 겹침 트러블슈팅 문서 추가 |
| mydocs/report/task_m100_142_report.md | #142 최종 보고서 추가 |
| mydocs/report/task_m100_139_report.md | #139 최종 보고서 추가 |
| mydocs/report/task_M07x_191_report.md | #191 결과 보고서 추가(요약) |
| mydocs/plans/task_m100_176_impl.md | #176 구현 계획서 추가 |
| mydocs/plans/task_m100_176.md | #176 수행계획서 추가 |
| mydocs/plans/task_m100_142_v2_impl.md | #142 v2 구현 계획서 추가 |
| mydocs/plans/task_m100_142_v2.md | #142 v2 수행계획서 추가 |
| mydocs/plans/task_m100_142_impl.md | #142 구현 계획서 추가 |
| mydocs/plans/task_m100_142.md | #142 수행계획서 추가 |
| mydocs/plans/task_m100_141_impl.md | #141 구현 계획서 추가 |
| mydocs/plans/task_m100_141.md | #141 수행계획서 추가 |
| mydocs/plans/task_m100_139_impl.md | #139 구현 계획서 추가 |
| mydocs/plans/task_m100_139.md | #139 수행계획서 추가 |
| mydocs/plans/task_m100_137.md | #137 수행계획서 추가 |
| mydocs/plans/task_M07x_191_impl.md | #191 구현 계획서 추가(요약) |
| mydocs/orders/20260418.md | 데일리 로그 추가 |
| mydocs/orders/20260417.md | 데일리 로그 추가 |
| mydocs/orders/20260416.md | 데일리 로그 추가 |
| mydocs/orders/20260414.md | 데일리 로그 갱신 |
| mydocs/orders/20260413.md | 데일리 로그 갱신 |
| mydocs/manual/MEMORY.md | 프로젝트 운영 메모 문서 추가 |
| mydocs/feedback/task139-eq-01.md | #139 피드백 문서 추가 |
| examples/hwpx_roundtrip.rs | HWPX roundtrip 예제 추가 |
| examples/hwpx_dump_text.rs | HWPX 텍스트 샘플 생성 예제 추가 |
| examples/hwpx_dump_empty.rs | HWPX 빈 문서 생성 예제 추가 |
| THIRD_PARTY_LICENSES.md | 참조 오픈소스(스펙/설계 참조) 고지 섹션 추가 |
| CLAUDE.md | output/ 하위 폴더 용도 문서화 갱신 |
| .github/workflows/deploy-pages.yml | docs/samples 등 변경 시 Pages 배포 스킵(paths-ignore) |
| .github/workflows/codeql.yml | docs/samples 등 변경 시 CodeQL 스킵(paths-ignore) |
| .github/workflows/ci.yml | docs/samples 등 변경 시 CI 스킵(paths-ignore) |
| samples/re-multisize-8-14.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-multisize-8-14-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-multisize-10-20.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-multisize-10-20-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-multisize-10-16.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-multisize-10-16-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-multisize-10-10.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-multisize-10-10-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-mixed-2tr.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-mixed-2tr-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-mixed-1tr.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-mixed-1tr-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-mixed-0tr.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-mixed-0tr-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-malgun.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-malgun-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-gulimche.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-gulimche-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-gulim.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-gulim-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-dotumche.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-dotumche-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-dotum.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-dotum-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-batangche.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-batangche-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-batang.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-font-batang-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-malgun.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-malgun-times.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-malgun-times-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-malgun-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-malgun-courier.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-malgun-courier-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-dotum.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-dotum-times.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-dotum-times-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-dotum-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-batangche.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-batangche-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-batang.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-batang-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-batang-arial.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-words-batang-arial-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-malgun.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-malgun-times.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-malgun-times-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-malgun-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-malgun-courier.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-malgun-courier-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-dotum.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-dotum-times.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-dotum-times-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-dotum-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-batangche.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-batangche-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-batang.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-batang-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-batang-arial.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-nospace-batang-arial-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-malgun.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-malgun-times.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-malgun-times-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-malgun-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-malgun-courier.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-malgun-courier-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-dotum.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-dotum-times.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-dotum-times-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-dotum-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-batangche.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-batangche-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-batang.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-batang-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-batang-arial.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-eng-mixed-batang-arial-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-right.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-right-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-left.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-left-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-justify.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-justify-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-center.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-align-center-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-06-punctuation.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-06-punctuation-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-05-mixed-koen.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-05-mixed-koen-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-04-digit-only.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-04-digit-only-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-03-latin-only.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-03-latin-only-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-02-space-count.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-02-space-count-empty.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-01-hangul-only.hwp | (바이너리) 샘플 파일 변경 |
| samples/re-01-hangul-only-empty.hwp | (바이너리) 샘플 파일 변경 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
edwardkim
approved these changes
Apr 19, 2026
Owner
There was a problem hiding this comment.
LGTM ✅
검증
- 로컬 머지 시뮬 (devel + pr-192): 자동 머지 성공, 충돌 0
- 변경 5개 파일 (input-handler-mouse, input-handler-picture, table-object-renderer + 보고서 2개)
- Rust lib 회귀: 891 테스트 그린
코드 검토
회전된 도형 편집 사용성 개선 — 회전각 반영 리사이즈 커서, Flip 처리, 트래킹/프리뷰 개선. 작성자 보고: cargo test 858 통과 + clippy 통과. 우리 환경 891 그린 확인.
코드가 깔끔해서 놀랐습니다. 좋은 기여 감사합니다. 이번 크롬, 엣지 패치에 기여자 추가합니다. 머지 진행합니다.
edwardkim
added a commit
that referenced
this pull request
Apr 19, 2026
edwardkim
added a commit
that referenced
this pull request
Apr 19, 2026
본 v0.5.0 → v0.7.3 (라이브러리) / 0.2.0 (확장) 배포 주기에 머지된 외부 기여자 6명을 README 3개 변경 이력에 추가: - @ahnbu — Ctrl+S file handle (PR #189, 기명시) - @bapdodi — 회전 도형 리사이즈 + Flip (PR #192) - @dreamworker0 — Windows CFB 경로 (PR #152) - @marsimon — HWP 그림 효과 SVG (PR #149) - @postmelee — 썸네일 + options CSP (PR #168) - @seunghan91 — HWPX Serializer + 다수 (PR #170, #161, #163, #153, #154) 각 README 끝에 "기여자 감사" 섹션 추가 — 6명 일괄 인정. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Apr 19, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[Update] PR 정리 완료
Copilot이 지적했던 불필요한 변경 사항(HWPX, 샘플 파일 등)을 모두 제거하고, 본 작업(#191)과 직접적으로 관련된 코드와 문서만 포함하도록 브랜치를 새로 정리(Cleaned up)했습니다.
변경 요약
회전된 도형의 편집 사용성 개선을 위해 다음 세 가지 핵심 기능을 구현했습니다.
관련 이슈
closes #191
테스트
cargo test통과 (858개 테스트 완료)cargo clippy -- -D warnings통과스크린샷