Skip to content

Commit ef67efa

Browse files
postmeleeedwardkim
authored andcommitted
Task #717: Fix table cell whitespace hit test
1 parent 1c783a8 commit ef67efa

11 files changed

Lines changed: 822 additions & 17 deletions

mydocs/orders/20260508.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
| **PR #675 Task #672** | TAC 표 비례 축소 임계값 강화 — 작은 차이 (≤2%) 면제 — closes #672 | **완료 (3 commits 단계별 보존 no-ff merge `877e020f` — 자동보정 모드 한정 정합, 그대로 보기 영역의 잔존 영역 PR #678 영역 처리)** | 컨트리뷰터 @jangster77 (Taesup Jang) — 14번째 사이클 PR (HWP 3.0 파서 영역 핵심 컨트리뷰터). 본질: `samples/계획서.hwp` 셀 [21] 영역의 raw_table_height (982.29) > common.height (969.53) 영역 차이 1.32% 영역에서도 영역 비례 축소 발동 영역 → 셀 콘텐츠 클립 영역. 한컴 권위: 작은 차이 영역 비례 축소 안 함. 정정: `src/renderer/height_measurer.rs:805` 영역 단일 분기 — `TAC_SHRINK_THRESHOLD_RATIO = 0.02` (2%) + 절대값 1px 보장 영역. 187 fixture sweep 분포: ≤2% 7 건 면제 (정정 효과) / ≥5% 11 건 보존 (의도적 압축). PR base 영역 PR #673 (Task #671) 영역 위 분기 영역이라 cherry-pick 영역에서 Task #672 영역 commits 만 영역 영역 (Task #671 영역은 PR #673 영역에서 머지). 본 환경 cherry-pick orders ours. 결정적 검증 1165 lib + svg_snapshot 7/7 + issue_546/issue_554 13/13 + clippy clean. 광범위 sweep 7 샘플 170 페이지: same=167 / diff=3 (계획서.hwp + 2010-01-06 p5 + synam-001 p19/p31 — 모두 영향 영역). WASM 빌드 4,589,098 bytes. **작업지시자 가설 점검**: "PR #673 A1 의 자동보정 정정 영역이 PR #675 의 본질 영역도 자연 해소?" → ❌ 미정합 (직접 측정: 그대로 보기 영역 SVG md5 다름 `b66efd77...` → `cc174155...` -706 bytes — 두 영역 본질 다름). **작업지시자 시각 판정**: 자동보정 영역 ★ 정합 (셀내 2줄 컨텐츠 세로 방향 정렬 한컴처럼 변경) / 그대로 보기 영역 클립핑 그대로 유지 (PR #678 영역 잔존). **작업지시자 결정 — 머지 유지 영역 (PR #678 머지 시 그대로 보기 영역의 클립핑 영역 자연 해소)**. 잔존 분리: Issue #674 → PR #678 (paragraph_layout 줄 위치 vs row_heights 정합 — 그대로 보기 영역의 클립핑 영역의 본질 영역). 검토 보고서: `mydocs/pr/archives/pr_675_review.md`. 처리 보고서: `mydocs/pr/archives/pr_675_report.md`. **`feedback_visual_judgment_authority` 권위 사례 강화** — 작업지시자 영역의 정밀 시각 판정 영역 (자동보정 영역 ★ 정합 + 그대로 보기 영역 잔존 분리 영역) 영역 결정적 검증 + 광범위 sweep 통과 영역 영역에도 영역 두 모드 영역의 차이 영역 검출 영역. **`feedback_pr_supersede_chain` 권위 사례 확장** — 동일 컨트리뷰터 영역의 다단계 본질 분리 영역 (PR #673 #671 → PR #675 #672 → PR #678 #674) 영역의 누적 영역 정합 영역. **`feedback_contributor_cycle_check`** 정합 — @jangster77 14번째 사이클 정확 표현 영역. |
1616
| **PR #673 Task #671** | 표 셀 내부 paragraph 줄바꿈 시 다중 LINE_SEG 줄 겹침 정정 — closes #671 | **완료 (3 commits 단계별 보존 no-ff merge `a6645ed7` + 메인테이너 후속 commit A1 `4d354d2e` 자동보정 정정)** | 컨트리뷰터 @jangster77 (Taesup Jang) — 13번째 사이클 PR (HWP 3.0 파서 영역의 핵심 영역 컨트리뷰터 — PR #451 부터 누적). `samples/계획서.hwp` 영역의 모든 셀 paragraph 영역의 line_segs.len() == 0 영역 — 한컴이 PARA_LINE_SEG 영역을 의도적으로 인코딩하지 않은 케이스. 본 환경 영역의 composer fallback 영역이 단일 ComposedLine 영역으로 압축 영역 → 한 줄 겹침 시각 결함. 본질 정정: `recompose_for_cell_width` 신규 함수 영역 (composer.rs) + 3중 가드 (line_segs.is_empty() / lines.len()==1 / 측정 폭 > cell_inner_width_px) + 6 곳 호출 (table_layout.rs, table_partial.rs, height_measurer.rs). **작업지시자 1차 시각 판정**: "그대로 보기 하면 2줄로 처리되지만 오히려 자동보정 선택하면 한줄로 겹쳐집니다" — 자동보정 모드 영역의 회귀 발견. **본질 점검**: `document.rs:270` (자동) + `:425` (사용자 명시 자동보정) 영역 모두 영역 `reflow_line_segs(cell_para, col_width, ...)` 영역 — column 폭 사용 영역 → 셀 paragraph LINE_SEG 영역 채움 영역 후 본 PR 가드 #1 영역 거짓 영역 → 정정 영역 미적용 영역. **A1 정정 (작업지시자 결정)**: 두 곳 영역 모두 영역 `cell_inner_width = hwpunit_to_px(cell.width) - padding.left - padding.right` 영역으로 정정 영역. 본 환경 cherry-pick simulation 충돌 0건 (orders 영역 ours). 결정적 검증 1165 lib + svg_snapshot 7/7 + issue_546/issue_554 13/13 + clippy clean. 광범위 sweep 7 샘플 170 페이지: same=170 / diff=0 ✅. WASM 빌드 4,589,092 bytes. **작업지시자 2차 시각 판정 ★ 성공** ("성공입니다") — 그대로 보기 + 자동보정 영역 모두 정합 영역. 셀 [13] 2줄 + 셀 [21] 3줄 정상 분리. 권위 자료 영구 보존 (`samples/계획서.hwp` 143KB) + 진단 도구 영구 보존 (inspect_task671.rs + inspect_task671_v2.rs). 잔존 분리: Issue #672 (TAC 표 비례 축소 시 셀 콘텐츠 클립 영역 — 별건 본질). 검토 보고서: `mydocs/pr/archives/pr_673_review.md`. 처리 보고서: `mydocs/pr/archives/pr_673_report.md`. **`feedback_visual_judgment_authority` 권위 사례 강화** — 결정적 검증 + 광범위 sweep 통과 영역에도 작업지시자 시각 판정 영역에서만 회귀 발견 영역의 권위 사례 영역. **`feedback_pr_supersede_chain` 권위 사례 확장** — PR + 메인테이너 후속 정정 영역의 통합 머지 영역 신규 패턴 영역 (시각 판정 영역에서 발견된 회귀 영역의 본질 영역 메인테이너 직접 정정 영역). **`project_hancom_lineseg_behavior`** 권위 사례 — 한컴 LINE_SEG 비표준 영역의 자체 재계산 영역의 본 환경 정정 영역 정합. |
1717
| **PR #664 Task #658** | rhwp-studio 드래그 선택 하이라이트 오버플로우 수정 — closes #658 | **완료 (4 commits 단계별 보존 no-ff merge, merge commit `c6bf769e`)** | 컨트리뷰터 @postmelee (Taegyu Lee) — 다회 사이클 영역 컨트리뷰터 (PR #339/#437/#510/#531/#642/#663 close → #664 재제출 / #718 후속). `samples/exam_social.hwp` 영역의 드래그 선택 하이라이트 영역이 페이지 폭 영역을 넘어 확장 영역. 본질: 선택 rect 시작/끝 오프셋 영역 모두 동일한 렌더 트리 hit 탐색 영역 사용 → 줄바꿈 경계 영역에서 같은 문자 오프셋 영역이 이전 줄 TextRun 끝 + 다음 줄 TextRun 시작 영역에 동시에 걸리는 영역 → 선택 시작점 영역이 이전 줄 끝 좌표 영역으로 해석 영역되어 오버플로우. 정정: `src/document_core/queries/cursor_nav.rs` 영역의 cursor hit bias 추가 (+118/-53 LOC) + `rhwp-studio/src/engine/selection-renderer.ts` 영역의 highlight div 재사용 (+50/-13) + caret-renderer + input-handler 영역의 가벼운 처리 영역 경로. **작업지시자 직접 결정**: "체리픽한 후, wasm 빌드해주세요. 이건은 메인테이너도 하려고 했던 작업입니다." 본 환경 cherry-pick simulation 충돌 0건 (orders 자동 머지). 결정적 검증 1165 lib + issue_658 2/2 (`body_multiline_selection_uses_next_line_start` + `data_cell_selection_rects_do_not_overflow_page`) + TypeScript 빌드 clean + clippy clean. WASM 빌드 4,584,723 bytes. **작업지시자 시각 판정 ★ 통과** ("PR 에서 해결하려고 했던 문제가 웹 에디터를 통해 해결되었다는 것을 확인했습니다") — exam_social.hwp 드래그 선택 하이라이트 페이지 폭 안 정합 (956.6px ≤ 1028.0px). 컨트리뷰터의 TDD Stage 1~4 + 후속 분리 (#661 → PR #718 영역) 절차 정합. 회귀 차단 가드 `tests/issue_658_text_selection_rects.rs` (2 케이스) + 진단 도구 `examples/inspect_658_selection.rs` 영구 보존. 검토 보고서: `mydocs/pr/archives/pr_664_review.md`. 처리 보고서: `mydocs/pr/archives/pr_664_report.md`. **`feedback_visual_judgment_authority` 권위 사례 강화** — 작업지시자 직접 영역 결정 영역의 cherry-pick + WASM 빌드 + 시각 판정 영역 정합. |
18+
| #717 | rhwp-studio 표 셀 빈 영역 클릭 시 커서 위치 이탈 정정 | 완료 | 완료: 18:45 / 중첩 표 내부 빈 영역 입력 경로까지 정정, native+WASM+studio build 통과, 초저높이 빈 셀 입력 가시성은 후속 분리 |
1819
| **PR #662 Task #656** | typeset/layout 모델 통일 — 분할 표 셀 마지막 visible 줄 클립 본질 정정 — closes #656 | **완료 (옵션 1 — 메인테이너 충돌 해결 통합 머지, merge commit `93ddeca7`, PR #657 epsilon supersede)** | 컨트리뷰터 @planet6897 (Jaeuk Ryu) — 16번째 사이클 PR. **PR #657 (Task #485) 영역의 epsilon 영역 supersede 영역의 후속 PR 영역**. 두 단계 영역의 정정: 1단계 (PR #657) epsilon 2.0px 휴리스틱 + limit_reached 플래그 → 2단계 (PR #662) epsilon 휴리스틱 → trail_ls 제외 일관 모델 영역의 본질 대체. **충돌 영역**: PR #662 base 가 PR #657 머지 이전이라 동일 함수 (`compute_cell_line_ranges`) 동일 hunk 충돌 영역 발생 (DIRTY/CONFLICTING). **작업지시자 결정**: "1번으로 합니다" — 메인테이너 충돌 해결 통합 머지 영역. **통합 정정**: epsilon 마진 삭제 → `abs_limit` 그대로 + break 비교 시 `line_break_pos = cum + h` (trail_ls 제외) + `limit_reached` 플래그 (Task #485 Bug-1) 보존 + atomic exceeds_limit `abs_limit` 정합. 본 환경 cherry-pick: Stage 1+2 깨끗 + Stage 3 메인테이너 통합 정정 commit (`85556094`) + Stage 4 orders ours + cleanup skip. 결정적 검증 1165 lib + svg_snapshot 7/7 + clippy clean. 광범위 sweep 7 샘플 170 페이지: same=166 / diff=4 (synam-001 영향 영역만). 본 환경 직접 재현: synam-001 p15 md5 변경 (`e9c0b084...` → `f978d183...`). WASM 빌드 4,573,882 bytes. **작업지시자 시각 판정 ★ 통과** ("통과입니다") — synam-001 p15 PartialTable OVERFLOW 해소 + form-002 page 0 분할 표 마지막 visible 줄 26 글자 ("ㅇPFC 나노산소운반체의 최적제조공정개발 및 GMP실증") 클립 해소. 검토 보고서: `mydocs/pr/archives/pr_662_review.md`. 처리 보고서: `mydocs/pr/archives/pr_662_report.md`. **`feedback_pr_supersede_chain` 권위 사례 강화 — 머지+머지 supersede 패턴 영역 신규 등록** — close+통합 머지 (PR #649→#650) vs 머지+supersede 머지 (PR #657→#662) 두 패턴 영역. **메인테이너 충돌 해결 영역의 권위 사례** — 컨트리뷰터 rebase 영역 부재 영역에서 메인테이너 직접 영역 통합 정정 영역의 정합 영역. |
1920
| **PR #657 Task #485** | synam-001.hwp 분할 표 셀 마지막 줄 클립 정정 — closes #485 | **완료 (옵션 A — 5 commits 단계별 보존 no-ff merge, merge commit `595c02d6`, 후속 분리 #656)** | 컨트리뷰터 @planet6897 (Jaeuk Ryu) — 15번째 사이클 PR. `samples/synam-001.hwp` 15·20·21 페이지 영역의 RowBreak 분할 표 (PartialTable) 영역 셀 마지막 줄 영역의 본문 경계 영역 클립 결함. **두 분리 버그 영역**: (1) Bug-1 (out-of-order) — `compute_cell_line_ranges` inner break 영역의 outer 차단 부재 영역에서 셀 마지막 단락 영역의 abs_limit fit 영역 시각 순서 역전 영역. (2) Bug-2 (boundary epsilon) — `line_end_pos > abs_limit` 영역의 boundary 케이스 (~0~2px 차이) 영역 fit 영역 cell-clip-rect bottom 침범 영역. 정정: `src/renderer/layout/table_layout.rs::compute_cell_line_ranges` 단일 함수 영역의 3 hunk (+28/-4 LOC) — `limit_reached` 플래그 + outer 차단 + `SPLIT_LIMIT_EPSILON = 2.0px` 영역 도입. 본 환경 cherry-pick simulation 충돌 0건 (orders/20260507.md 자동 머지). 결정적 검증 1165 lib + clippy clean. 광범위 sweep 7 샘플 170 페이지: same=166 / diff=4 (synam-001 p5/p15/p20/p21) — 다른 6 샘플 (135 페이지) 회귀 0 ✅. WASM 빌드 4,573,826 bytes. **작업지시자 시각 판정 ★ 통과** ("메인테이너 시각 검증 통과했습니다") — synam-001 p15 (pi=84 cell-last slip 차단), p20 (pi=169 cell-last slip 차단), p21 (pi=108 epsilon 마진), p5 (PartialTable pi=69 split table 추가 영향 영역의 정정 영역 정합). 컨트리뷰터의 TDD Stage 1~4 영역 절차 정합. **후속 영역 분리 영역 정합** — Issue #656 (typeset/layout height 측정 모델 통일) 별도 등록 영역, 작업지시자 영역의 review 범위 영역 외 영역 명시 ("후속작업은 이미 컨트리뷰터가 분리했기에 이 리뷰 범위에서 제외"). 검증용 PDF 영구 보존 (`samples/synam-001.pdf`). 검토 보고서: `mydocs/pr/archives/pr_657_review.md`. 처리 보고서: `mydocs/pr/archives/pr_657_report.md`. **`feedback_visual_judgment_authority` 권위 사례 강화** — 광범위 sweep byte 차이 영역의 회귀/정정 판정 영역의 작업지시자 시각 판정 영역에서 직접 영역 통과 영역의 정합 영역. **`feedback_v076_regression_origin` 권위 사례** — 컨트리뷰터 환경 (synam-001.pdf 대조) + 작업지시자 한컴 편집기 환경 모두 시각 판정 통과 영역의 환경 차이 회귀 가능성 차단 영역. **`feedback_pr_supersede_chain` 권위 사례** — 후속 영역 (#656) 분리 영역의 review 범위 외 영역 명시 영역의 정합 영역. |
2021
| **PR #650 Task #517+#518 (재적용)** | Layout 리팩터링 Phase 1+2 누락 회귀 정정 — closes #647 + #648 | **완료 (옵션 B — squash merge → 1 commit 축약, merge commit `e8f93dee`)** | 컨트리뷰터 @planet6897 (Jaeuk Ryu) — 14번째 사이클 PR. PR #649 close 영역의 통합 후속 처리 영역. 두 commit (`ffb32ff7` Task #517 Phase 1 + `e8dd3f0f` Task #518 Phase 2) 영역의 squash merge 영역. **Phase 1 (Task #517)**: `layout_debug_enabled()` env-var 헬퍼 (`RHWP_LAYOUT_DEBUG=1`) + `LAYOUT_INLINE_TABLE_PARA` / `LAYOUT_LS` / `LAYOUT_INLINE_TBL` / `LAYOUT_BREAK_INDICES` 진단 로깅 + `scripts/svg_regression_diff.sh` (build/diff 두 모드, 7 샘플 170 페이지 byte 비교 영역). **Phase 2 (Task #518)**: `line_break_char_idx: Option<usize>` → `line_break_char_indices: Vec<usize>` 다중화. `ctrl_gap` 합산 (saturating 0 → 항상 None) → `char_offsets[i] >= ts` 직접 룩업 알고리즘 영역 정정. `ls[1]` 만 → `ls[1..]` 모두 (3줄 이상 wrap 케이스 영역). 본 환경 cherry-pick simulation 충돌 0건 (Auto-merging `paragraph_layout.rs` 자동 정합). 결정적 검증 1165 lib pass + clippy clean. **광범위 sweep 7 샘플 170 페이지: same=170 / diff=0 ✅** (PR 본문 명시 `same=167/diff=3` 와 차이 — 회귀 케이스 본 환경 fixture 영역 노출 부재 영역). WASM 빌드 산출물 갱신. **시각 판정 게이트 면제 영역 정합** — 작업지시자 직접 영역 결정 ("이 PR 은 시각 판정없이 앞선 PR #649 에 연결된 처리"). PR #649 close 영역의 단순 cherry-pick 영역의 통합 후속 처리 영역의 정합. **묶음 머지 a7e43f9 영역 잔여 task**: ✅ Task #519 (PR #620), ✅ Task #517+#518 (PR #650), ❓ Task #520/#521/#523/#528 (별도 점검 영역 권장). 검토 보고서: `mydocs/pr/archives/pr_650_review.md`. 처리 보고서: `mydocs/pr/archives/pr_650_report.md`. **`feedback_close_issue_verify_merged` 권위 사례 강화** — 묶음 머지 누락 영역의 본질 정정 영역의 통합 처리 영역 정합. **신규 메모리 룰 영역 등록 영역**: `feedback_pr_supersede_chain` — PR close 영역의 통합 후속 처리 영역의 패턴 영역 (작업지시자 결정 시점 영역의 의도 영역 보존 영역). |

mydocs/plans/task_m100_717.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Task M100 #717 수행 계획서
2+
3+
## 작업 개요
4+
5+
- 이슈: #717 `rhwp-studio: 표 셀 빈 영역 클릭 시 커서가 다른 위치로 이동`
6+
- 브랜치: `local/task717`
7+
- 대상 문서: `samples/exam_social.hwp`
8+
- 대상 화면: `rhwp-studio` web, 1/4쪽 왼쪽 첫 번째 자료 표
9+
10+
## 현상 요약
11+
12+
`samples/exam_social.hwp` 1/4쪽에서 왼쪽 첫 번째 자료 표의 제목 행 빈 영역을 클릭하면, 클릭한 표/셀 내부가 아니라 페이지 하단의 작은 번호 표(`32`) 쪽으로 커서가 이동한다.
13+
14+
이슈 기준 클릭 좌표는 `x≈191, y≈356`이며, SVG 디버그 오버레이 기준 대상 표는 `s0:pi=1 ci=0 1x1`이다.
15+
16+
## 사전 분석
17+
18+
확인한 경로:
19+
20+
- `src/document_core/queries/cursor_rect.rs::hit_test_native`
21+
- `rhwp-studio/src/engine/input-handler-mouse.ts`
22+
- `tests/issue_658_text_selection_rects.rs`
23+
- `tests/issue_595.rs`
24+
25+
현재 `input-handler-mouse.ts`의 일반 클릭 경로는 WASM `hitTest(pageIdx, pageX, pageY)` 결과를 그대로 `cursor.moveTo(hit)`에 전달한다. 따라서 본질 정정 위치는 Rust/WASM의 `hit_test_native()` 쪽이 우선이다.
26+
27+
의심되는 본질 원인:
28+
29+
1. `hit_test_native()``cell_bboxes` 메타를 보완할 때 `ctx.path[0].cell_index == cb.cell_index`만으로 TextRun을 찾는다.
30+
2. 문서 내 여러 표와 바탕쪽 표는 모두 `cell_index=0`, `cell_index=1` 같은 낮은 인덱스를 반복 사용한다.
31+
3. 이 때문에 클릭한 셀 bbox의 좌표는 맞더라도, 메타 보완 단계에서 다른 표나 바탕쪽 표의 `parent_para_index/control_index`로 덮일 수 있다.
32+
4. 특히 대상 자료 표 내부에는 중첩 표가 있고, `CellBboxInfo`는 현재 전체 `cellPath`를 보존하지 않으므로 중첩 셀의 빈 영역 클릭을 안정적으로 해당 셀 컨텍스트에 고정하지 못한다.
33+
5. 셀 내부 클릭으로 판정된 뒤에도 해당 셀 run을 찾지 못하면 전역 본문 fallback으로 진행할 수 있어, 클릭한 표와 무관한 위치로 커서가 이동할 위험이 있다.
34+
35+
## 작업 범위
36+
37+
- `hit_test_native()`의 셀 bbox 기반 hitTest를 표/셀 컨텍스트 기준으로 안정화한다.
38+
- 표 셀 내부 클릭은 해당 셀 또는 해당 셀의 가장 가까운 TextRun/문단 위치로 귀속한다.
39+
- 셀 내부 클릭으로 판정된 뒤에는 본문 전체, 바탕쪽 표, 다른 표의 fallback으로 빠지지 않도록 한다.
40+
- 필요한 경우 `CellBboxInfo`에 클릭 bbox와 연결된 셀 경로 정보를 보강한다.
41+
- `samples/exam_social.hwp` 기반 회귀 테스트를 추가한다.
42+
43+
## 범위 제외
44+
45+
- 표 객체 선택/경계선 클릭 UX 변경
46+
- 헤더/푸터 hitTest 정책 변경
47+
- 글상자/수식 더블클릭 정책 변경
48+
- 렌더링 배치, 표 레이아웃, 페이지네이션 변경
49+
50+
## 검증 기준
51+
52+
- `samples/exam_social.hwp` 1/4쪽 `s0:pi=1 ci=0` 자료 표 제목 행 빈 영역 클릭 좌표가 같은 표/셀 컨텍스트로 귀속되어야 한다.
53+
- 왼쪽 `<보기>` 표(`s0:pi=6 ci=0 3x3`) 등 다른 표의 빈 영역 클릭도 해당 표/셀 내부로 귀속되어야 한다.
54+
- 페이지 하단 번호 표 또는 바탕쪽 영역으로 커서가 이동하지 않아야 한다.
55+
- 기존 회귀 영역을 유지한다.
56+
- #661/#658 드래그 선택 관련 selection rect
57+
- #595 수식 더블클릭/header-footer hitTest
58+
- #686 master page 글상자 관련 영역은 별도 이슈 범위로 보존
59+
- 표 객체 선택/경계선 클릭
60+
61+
## 승인 요청
62+
63+
본 수행 계획서 승인 후 다음 단계로 구현 계획서(`mydocs/plans/task_m100_717_impl.md`)를 작성한다. 구현 계획서는 최소 3단계, 최대 6단계로 나누고, 구현 계획서 승인 전에는 소스 코드를 수정하지 않는다.

0 commit comments

Comments
 (0)