fix: 표 셀 빈 영역 hitTest 컨텍스트 이탈 정정 (closes #717)#725
Conversation
본질: rhwp-studio 영역 의 텍스트 드래그 선택 중 커서 / 스크롤 위치 영역 포인터 영역 무관 영역 의 튐 결함 정정. 기존 경로: mousemove 마다 hit-test → cursor focus 이동 → caret 갱신 + scrollCaretIntoView() 호출 → 선택 focus 의 다른 페이지/문단 순간 이동 시 스크롤 컨테이너 가 caret rect 추적 → 사용자 드래그 위치 ↔ 문서 스크롤 함께 튐. 정정 (드래그 중 caret 갱신 + 스크롤 책임 분리): 1. caret: 선택 상태 표시만 갱신 (scrollCaretIntoView 부재) 2. 스크롤: 포인터 edge 감지만 담당 (RAF 루프 + edge 48 px + step 2~20 px) 3. 편집 영역 외부 영역 도 드래그 지속 (document-level mousemove 등록/해제) 4. 포인터 좌표 저장 + 스크롤 발생 시 동일 좌표로 hit-test 재계산 신규 헬퍼 (input-handler.ts +128 LOC): - startTextSelectionDrag / stopTextSelectionDrag - updateTextSelectionDragPointer / updateTextSelectionDragFromPointer - hitTestFromClientPoint (clientX/Y parameter 분리) - updateTextSelectionDragAutoScroll / runTextSelectionDragAutoScroll - updateCaretDuringDrag (드래그 중 caret 갱신) input-handler-mouse.ts (+6/-9): - 3 곳 isDragging=true → startTextSelectionDrag(e) (드래그 시작 시 포인터 좌표 보존 + document mousemove 등록) - mousemove 분기: hit-test 직접 호출 → updateTextSelectionDragFromPointer 래퍼 (저장된 포인터 좌표 사용) - mouseup: isDragging=false → stopTextSelectionDrag 회귀 가드 e2e (drag-selection-autoscroll.test.mjs +86 LOC): - 70줄 문서 + 첫 줄 → 하단 edge 드래그 - scrollTop 0 → 1529 / hasSelection=true / focus 문단 69 / highlight 70 메인테이너 통합 정정 영역 (충돌 해결): - input-handler-mouse.ts (mousemove 분기): PR #718 영역 의 updateTextSelectionDragFromPointer 영역 채택 - input-handler.ts (hitTestFromClientPoint): PR #718 영역 의 clientX/Y parameter 영역 + devel 영역 의 PR #693 (Task #685+#689) getPageAtPoint (그리드 모드 click 좌표 정합) 영역 통합 - input-handler.ts (updateCaretDuringDrag): PR #718 영역 의 scrollCaretIntoView 부재 본질 + devel 영역 의 PR #664 (Task #658) caret.updateLive (깜박임 타이머 유지 본질) 영역 통합 검증: - cargo test --release: lib 1173 + 통합 ALL GREEN, failed 0 - cargo clippy --release: 신규 경고 0 - npx tsc --noEmit (rhwp-studio): clean - npm run build (rhwp-studio): PWA 정상 분리된 후속: - Issue #717: 표 셀 빈 영역 클릭 hit-test (PR #725 별도 처리 영역) Closes #661 Co-Authored-By: Taegyu Lee <86018802+postmelee@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- mydocs/pr/archives/pr_718_review.md (검토 문서, 충돌 본질 분석 + 메인테이너 통합 정정 방향)
- mydocs/pr/archives/pr_718_report.md (처리 보고서, 3건 충돌 해결 명시)
- mydocs/plans/archives/task_m100_661{,_impl}.md
- mydocs/orders/20260509.md: PR #718 행 + 본 사이클 패턴 라인 추가
처리 결과:
- 옵션 A — 5 commits 단계별 보존 cherry-pick + 메인테이너 통합 정정 + no-ff merge (95eea5f)
- 작업지시자 시각 판정 ★ 통과 (웹 에디터, 블럭 드래그 선택 기능)
- 충돌 3건 메인테이너 통합 정정 (PR #693 getPageAtPoint + PR #664 updateLive 영역 + PR #718 본질 영역 양립)
- WASM 빌드 4,607,734 bytes
- Issue #661 close 자동 정합
분리된 후속: Issue #717 OPEN (PR #725 별도 처리 영역)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #725 (@postmelee) 옵션 A 처리 — 1 commit cherry-pick + no-ff merge. 본질 정정 (cursor_rect.rs): - RunInfo / CellBboxInfo 영역 table_id: Option<u32> 추가 (소속 표 RenderNode id) - collect_runs() 영역 current_table_id 인자 추가 — Table 노드 진입 시 Some(node.id) 자식 전파 - cell_bboxes meta 보완 영역 영역 r.table_id == cb.table_id 격리 (같은 표 영역 만 매칭) - 중첩 표 영역 cellPath 보존 — innermost() 영역 cell_index 매칭 + cell_context 클론 + 최내곽 cell_index/cell_para_index/text_direction 갱신 - clicked_cell 선택 영역 영역 가장 작은 bbox (.min_by_key on w*h) — 중첩 표 내부 셀 우선 - 빈 셀 fallback 영역 전체 cellPath 직렬화 (path entries → JSON 배열) 회귀 가드 3건 신규 (tests/issue_717_table_cell_hit_test.rs): - 자료 표 제목 행 빈 영역 클릭 영역 자료 표 안 caret 유지 - 회색 헤더 내부표 빈 영역 영역 cellPath=[(0,0,0),(1,1,0)] 보존 + path 기반 X 삽입 영역 getTextInCellByPath/getCursorRectByPath 정상 - <보기> 표 빈 영역 영역 caret <보기> 표 안 유지 자기 검증: - cargo build --release ✅ - cargo test --release: ALL GREEN, failed 0 (신규 3 PASS) - cargo clippy: 48 errors 영역 모두 기존 코드 (devel 52 → 본 PR 48, 4건 정정 영역) — 본 PR 무관 - 광범위 sweep: 7 fixture / 170 페이지 / 회귀 0 ✅ - 시각 판정 면제 합리 — cursor_rect.rs query API, 시각 출력 무영향, 회귀 가드 통과 후속 분리 (PR 본문 명시): - 회색 헤더 내부표 영역 의 극단적 낮은 빈 셀 (~5.1px) 영역 영역 입력 가시성 영역 영역 별건 — "초저높이 빈 셀 편집 진입/표 선택 UX 정책" 영역 후속 closes #717
- mydocs/pr/archives/pr_725_review.md: 검토 문서 archives 이동 - mydocs/pr/archives/pr_725_report.md: 처리 보고서 작성 · cursor_rect.rs 영역 table_id 격리 + 중첩 표 cellPath 보존 · 회귀 가드 3건 신규 + 광범위 sweep 170/170 same · 시각 판정 면제 합리 (query API + 시각 출력 무영향) - mydocs/plans/archives/task_m100_717.md(_impl).md: plans archives 이동 - mydocs/orders/20260510.md: PR #725 항목 추가 (5/10 사이클 패턴 영역 영역 PR #720/#723/#725 영역 3건)
|
@postmelee 님, 검토 + 머지 완료했습니다. 처리 결과옵션 A (1 commit cherry-pick + no-ff merge `bbf01424`) 로 처리. 자기 검증
시각 판정 면제`cursor_rect.rs` query API 만 변경 영역 — SVG/PNG 시각 출력 무영향 영역. 회귀 가드 3건 + 광범위 sweep 0 회귀 보장 영역 → `feedback_visual_judgment_authority` 정합 영역 영역 면제 합리. PR 본문 영역 영역 before/after 영상 첨부 영역 영역 시각 입증 정합. 본질 정정 영역`table_id` 영역 영역 의 격리 영역 영역 `cellIndex` 일반화 영역 결함 본질 영역. 중첩 표 영역 `cellPath` 영역 보존 (path 기반 `getCursorRectByPath()` / `getTextInCellByPath()` API 정합). `feedback_hancom_compat_specific_over_general` 영역 의 권위 사례 영역 — case 가드 영역 영역 일반화 보다 안전. 처리 보고서: `mydocs/pr/archives/pr_725_report.md`. 후속 분리 (PR 본문 명시 영역 정합)회색 헤더 내부표 영역 의 극단적 낮은 빈 셀 (~5.1px) 영역 영역 입력 가시성 영역 영역 별건 — "초저높이 빈 셀 편집 진입/표 선택 UX 정책" 영역 후속 작업. @postmelee 님 15+ 사이클 (rhwp-studio editor 영역 핵심) 컨트리뷰션 영역 영역 5/10 사이클 영역 PR #720/#723/#725 영역 3건 처리 완료 영역. |
요약
samples/exam_social.hwp1/4쪽 왼쪽 자료 표의 제목 행 빈 영역을 클릭하면 커서가 페이지 하단 번호 표(32) 쪽으로 이동하던 문제를 수정했습니다.hit_test_native()가 표/셀 bbox 메타를 보완할 때cellIndex만으로 다른 표의 TextRun 컨텍스트를 섞던 문제를 제거했습니다.cellPath를 보존하도록 보강했습니다.Closes #717
시각적 변경사항 비교
변경 전
2026-05-09.00.23.06.mov
변경 후
2026-05-09.00.23.22.mov
원인
src/document_core/queries/cursor_rect.rs::hit_test_native()에서TableCellbbox 메타를 보완할 때cellIndex만 기준으로 TextRun을 찾았습니다.HWP 문서에서는 여러 표와 바탕쪽 표가 모두
cellIndex=0같은 낮은 인덱스를 반복 사용합니다. 이 때문에 클릭 좌표는s0:pi=1 ci=0자료 표 내부였지만, hit-test 결과가 페이지 하단 번호 표 쪽 컨텍스트로 오염될 수 있었습니다.후속 확인 중에는 중첩 표의
TableCellbbox가 전체cellPath를 잃고 최외곽 표의 셀처럼 반환되는 문제도 확인했습니다. 예를 들어 회색 헤더 내부표의 빈 영역은[(0,0,0),(1,1,0)]경로로 들어가야 하지만, 기존 로직은 내부표cellIndex=1을 최외곽1x1표의cellIndex=1처럼 다룰 수 있었습니다.변경 사항
RunInfo와CellBboxInfo에 소속 표RenderNode id를 기록했습니다.RenderNode id범위 안의 TextRun만 사용하도록 제한했습니다.cell_context를 템플릿으로 사용해 전체cellPath를 복원했습니다.RenderNode id와 최내곽cellIndex를 함께 비교하도록 했습니다.cellPath를 반환하도록 했습니다.회귀 테스트
tests/issue_717_table_cell_hit_test.rs를 추가했습니다.검증 좌표:
page=0, x=191.0, y=356.0parentParaIndex=1,controlIndex=0, caret가 자료 표 안에 유지page=0, x=100.0, y=350.0cellPath=[(0,0,0),(1,1,0)], path 기반 삽입/커서 조회 가능<보기>표 빈 영역page=0, x=110.0, y=865.0parentParaIndex=6,controlIndex=0, caret가<보기>표 안에 유지회색 헤더 내부표 케이스는 hit-test 결과만 보지 않고, 반환된
cellPath로X를 삽입한 뒤getTextInCellByPath()와getCursorRectByPath()가 정상 동작하는지까지 확인합니다.검증
cargo test --test issue_717_table_cell_hit_test -- --nocapturecargo test --lib --releasecd rhwp-studio && npm run buildcargo test --test issue_595cargo test --test issue_658_text_selection_rectsdocker-compose --env-file .env.docker run --rm wasm후속 작업
작업지시자 시각 확인에서 회색 헤더 내부표의 극단적으로 낮은 빈 셀에 텍스트가 입력되지만 보이지 않는 현상을 확인했습니다.
해당 셀은 실제 파일 구조상 높이 약
5.1px의 장식/간격용 내부표 셀입니다. 입력 경로 자체는 이 PR에서 올바른cellPath로 들어가도록 정정됐으므로, 이 잔여 현상은 #717의 커서 이탈 결함 범위를 넘는 “초저높이 빈 셀 편집 진입/표 선택 UX 정책” 후속 작업으로 분리했습니다.본 PR 영역
src/document_core/queries/cursor_rect.rstests/issue_717_table_cell_hit_test.rsmydocs/plans/task_m100_717.mdmydocs/plans/task_m100_717_impl.mdmydocs/working/task_m100_717_stage{1..5}.mdmydocs/report/task_m100_717_report.mdmydocs/orders/20260508.md