현상
첨부 영상(화면 기록 2026-05-07 12.57.50.mov) 기준으로, rhwp-studio web 편집 화면에서 텍스트를 마우스로 드래그 선택할 때 선택 영역이 정상적으로 유지되지 않고 화면이 버벅인다.
2026-05-07.13.28.24.mov
영상 관찰 환경:
실행 경로: Firefox 확장 viewer (moz-extension://.../viewer.html)
문서: exam_social1.hwp
관찰 위치: 오른쪽 박스/자료 영역 내부 텍스트
영상: 6.16초, 3248x2122, 약 58fps
관찰된 동작:
텍스트 드래그 시 파란 선택 하이라이트가 생성되기는 한다.
그러나 일부 줄의 선택 하이라이트 폭이 실제 텍스트/박스 영역을 벗어나 오른쪽 페이지 바깥 회색 영역까지 길게 튄다.
드래그 중 하이라이트가 줄 단위로 안정적으로 유지되지 않고, 넓게 튀었다가 사라지는 동작이 반복된다.
드래그 중 화면이 버벅이며, 선택 종료 후 사용자가 기대한 텍스트 선택 상태가 정상적으로 남지 않는 것처럼 보인다.
즉 본질은 "선택 기능 미동작"이라기보다 선택 rect 계산이 잘못되어 페이지/박스 밖으로 튀고, 그 잘못된 rect를 매 프레임 DOM으로 재생성하면서 드래그 UX가 무너지는 문제 로 보인다.
업스트림/기존 이슈 확인
2026-05-07 기준 upstream/devel 최신화 후 확인:
기준 커밋: e7ae428
local/devel...upstream/devel: 0 / 0
관련 검색 결과:
텍스트 선택 드래그
selection drag rhwp-studio
버벅 / 느림 / 성능 rhwp-studio
마우스 선택 rhwp-studio
정확히 같은 열린 이슈/PR은 확인되지 않았다.
인접 이슈:
의심 지점
1. 드래그 루프가 매 rAF마다 무거운 선택 갱신을 수행
rhwp-studio/src/engine/input-handler-mouse.ts
// 드래그 중: requestAnimationFrame으로 throttle하여 성능 확보
if ( this . isDragging ) {
if ( this . dragRafId ) return ;
this . dragRafId = requestAnimationFrame ( ( ) => {
this . dragRafId = 0 ;
if ( ! this . isDragging ) return ;
const hit = this . hitTestFromEvent ( e ) ;
if ( hit && hit . paragraphIndex < 0xFFFFFF00 ) {
this . cursor . moveTo ( hit ) ;
this . updateCaret ( ) ;
}
} ) ;
return ;
}
드래그 중 매 프레임:
hitTestFromEvent(e)
cursor.moveTo(hit) → CursorState.updateRect()
updateCaret()
updateSelection()
이 전체 경로가 실행된다. 선택 rect 계산이 무겁거나 잘못된 rect를 반환하면 화면이 즉시 버벅일 수 있다.
2. updateCaret()가 드래그 중에도 항상 updateSelection() 호출
rhwp-studio/src/engine/input-handler.ts
private updateCaret ( ) : void {
...
this . updateSelection ( ) ;
this . emitCursorFormatState ( ) ;
this . updateFieldMarkers ( ) ;
...
}
드래그 중에는 커서 시각 갱신과 선택 rect 갱신이 강하게 결합되어 있다. 선택 rect만 갱신하면 되는 상황에서도 캐럿 스크롤/필드 마커/서식 상태 emit까지 동반될 수 있다.
3. SelectionRenderer가 매번 div를 전부 삭제하고 재생성
rhwp-studio/src/engine/selection-renderer.ts
render ( rects : SelectionRect [ ] , zoom : number ) : void {
this . clear ( ) ;
this . ensureAttached ( ) ;
...
for ( const rect of rects ) {
const div = document . createElement ( 'div' ) ;
...
this . layer . appendChild ( div ) ;
this . highlights . push ( div ) ;
}
}
긴 다중 줄 선택에서는 드래그 프레임마다:
기존 highlight DOM 전부 remove
새 div 다수 생성
style 문자열 전체 재할당
이 반복된다. 영상의 버벅임은 이 DOM churn의 영향일 가능성이 높다.
4. native selection rect 계산이 박스/셀/단 영역으로 클리핑되지 않는 것으로 보임
src/document_core/queries/cursor_nav.rs::get_selection_rects_native
의심 포인트:
get_selection_rects_native()가 반환하는 rect의 width가 실제 텍스트 컨테이너 폭을 넘어간다.
영상에서 오른쪽 자료 박스 내부 텍스트를 선택할 때 하이라이트가 박스 경계뿐 아니라 페이지 오른쪽 바깥 회색 영역까지 확장된다.
이는 SelectionRenderer가 단순히 left = pageLeft + rect.x * zoom, width = rect.width * zoom을 신뢰하기 때문에 native rect 오류가 그대로 화면에 드러난 것으로 보인다.
특히 아래 분기 점검 필요:
let width = if selection_continues {
( area_right - rect_x) . max ( 0.0 )
} else if !partial_start && cell_ctx. is_none ( ) {
( rh. x - rect_x) . max ( 0.0 )
} else {
( rh. x - lh. x ) . abs ( )
} ;
점검해야 할 사항:
lh와 rh가 같은 줄/같은 컨테이너의 커서 hit인지
range_end가 줄 끝/비렌더링 문자일 때 right_hit가 다음 줄 또는 다른 컨테이너 hit로 잡히지 않는지
cell_ctx.is_none() 경로에서 find_column_area()만 기준으로 삼아야 하는지, 글상자/박스/표 내부 텍스트에서 별도 컨테이너 bbox가 필요한지
cell_ctx=Some 경로도 셀 bbox로 rect_x..rect_x+width 클램프가 필요한지
예상 해결 방향
Stage 1. 재현/계측
영상 시나리오를 기준으로 exam_social1.hwp의 오른쪽 박스 텍스트 드래그를 재현한다.
드래그 중 다음 값을 임시 로그 또는 e2e 계측으로 수집한다.
hitTestFromEvent 결과: sectionIndex, paragraphIndex, charOffset, parentParaIndex, controlIndex, cellIndex, isTextBox, cursorRect
getSelectionRects*() 반환 rect 배열: pageIndex, x, y, width, height
선택 rect가 페이지 폭/컬럼/셀/글상자 bbox를 초과하는 순간
exam_math.hwp 2페이지부터 수식 더블클릭 hitTest 오동작 — 1페이지만 정상 #595 / PR #645의 hitTestHeaderFooter 정정과 무관하게 본 증상이 재현되는지 확인한다.
Stage 2. native selection rect 정합화
src/document_core/queries/cursor_nav.rs::get_selection_rects_native를 우선 점검/수정한다.
권장 방향:
선택 rect는 실제 TextRun bbox와 해당 줄의 컨테이너 bbox를 기준으로 계산한다.
lh와 rh가 다른 줄/다른 컨테이너에서 온 경우, 줄 끝 rect 계산을 별도로 처리한다.
본문/다단은 column area로, 셀 내부는 cell bbox로, 글상자 내부는 textbox/cell-context bbox로 클램프한다.
최종 rect는 최소한 페이지 영역 밖으로 나가지 않도록 0..page.width, 0..page.height로 방어 클램프한다.
selection_continues일 때도 무조건 column 끝까지 확장하기보다 현재 줄의 실제 컨테이너 끝을 사용한다.
완료 조건:
선택 하이라이트가 페이지 바깥 회색 영역으로 확장되지 않는다.
오른쪽 자료 박스 내부 드래그 선택이 박스/텍스트 줄 범위 안에서 안정적으로 표시된다.
기존 본문 다단 선택 회귀가 없어야 한다.
Stage 3. frontend 드래그 성능 개선
정확도 수정 후에도 버벅임이 남으면 rhwp-studio 쪽을 최적화한다.
권장 방향:
SelectionRenderer.render()에서 div 전량 삭제/재생성 대신 기존 div pool 재사용.
rect 배열이 이전 프레임과 동일하면 DOM 업데이트 생략.
드래그 중 updateCaret() 전체를 호출하지 않고, 선택 갱신 전용 경량 경로를 분리하는 방안 검토.
드래그 중 scrollCaretIntoView, emitCursorFormatState, updateFieldMarkers 호출 빈도 제한.
완료 조건:
긴 다중 줄 드래그 선택에서도 프레임 드랍이 눈에 띄지 않는다.
하이라이트가 깜빡이거나 선택 종료 시 사라지는 현상이 없어야 한다.
회귀 테스트 제안
Native/Rust
get_selection_rects_native()에 대해:
같은 문단 다중 줄 선택
표/셀 내부 다중 줄 선택
글상자/박스 내부 다중 줄 선택
다단 문서 선택
각 rect에 대해 다음 조건을 검증한다.
x >= 0
width > 0
x + width <= page_width + epsilon
컨테이너 bbox가 있는 경우 x..x+width가 컨테이너 bbox를 초과하지 않음
rhwp-studio e2e
rhwp-studio/e2e/text-selection-drag.test.mjs 후보:
샘플 문서 로드
오른쪽 박스 텍스트 영역에서 mouse down → move → up
.selection-layer 하이라이트 div들의 getBoundingClientRect() 수집
모든 하이라이트가 페이지 흰 영역 또는 대상 박스 영역 안에 있는지 검증
드래그 종료 후 선택 하이라이트가 유지되는지 검증
비목표
네이티브 브라우저 텍스트 선택으로 전환
클립보드 포맷 개선
#595의 머리말/꼬리말 hit-test 정정 자체
본 이슈는 마우스 드래그 텍스트 선택의 rect 정확도와 드래그 중 렌더링 성능 에 한정한다.
현상
첨부 영상(
화면 기록 2026-05-07 12.57.50.mov) 기준으로,rhwp-studioweb 편집 화면에서 텍스트를 마우스로 드래그 선택할 때 선택 영역이 정상적으로 유지되지 않고 화면이 버벅인다.2026-05-07.13.28.24.mov
영상 관찰 환경:
moz-extension://.../viewer.html)exam_social1.hwp관찰된 동작:
즉 본질은 "선택 기능 미동작"이라기보다 선택 rect 계산이 잘못되어 페이지/박스 밖으로 튀고, 그 잘못된 rect를 매 프레임 DOM으로 재생성하면서 드래그 UX가 무너지는 문제로 보인다.
업스트림/기존 이슈 확인
2026-05-07 기준
upstream/devel최신화 후 확인:e7ae428local/devel...upstream/devel: 0 / 0관련 검색 결과:
텍스트 선택 드래그selection drag rhwp-studio버벅 / 느림 / 성능 rhwp-studio마우스 선택 rhwp-studio정확히 같은 열린 이슈/PR은 확인되지 않았다.
인접 이슈:
hitTestHeaderFooter오동작 및 본문 hit-test 침범 문제. 본 이슈와 같은 마우스/hit-test 영역이지만, 영상의 주 증상인 텍스트 선택 rect가 페이지 밖으로 튀는 문제와는 별도 결함으로 분리한다.의심 지점
1. 드래그 루프가 매 rAF마다 무거운 선택 갱신을 수행
rhwp-studio/src/engine/input-handler-mouse.ts드래그 중 매 프레임:
hitTestFromEvent(e)cursor.moveTo(hit)→CursorState.updateRect()updateCaret()updateSelection()이 전체 경로가 실행된다. 선택 rect 계산이 무겁거나 잘못된 rect를 반환하면 화면이 즉시 버벅일 수 있다.
2.
updateCaret()가 드래그 중에도 항상updateSelection()호출rhwp-studio/src/engine/input-handler.ts드래그 중에는 커서 시각 갱신과 선택 rect 갱신이 강하게 결합되어 있다. 선택 rect만 갱신하면 되는 상황에서도 캐럿 스크롤/필드 마커/서식 상태 emit까지 동반될 수 있다.
3. SelectionRenderer가 매번 div를 전부 삭제하고 재생성
rhwp-studio/src/engine/selection-renderer.ts긴 다중 줄 선택에서는 드래그 프레임마다:
이 반복된다. 영상의 버벅임은 이 DOM churn의 영향일 가능성이 높다.
4. native selection rect 계산이 박스/셀/단 영역으로 클리핑되지 않는 것으로 보임
src/document_core/queries/cursor_nav.rs::get_selection_rects_native의심 포인트:
get_selection_rects_native()가 반환하는 rect의width가 실제 텍스트 컨테이너 폭을 넘어간다.SelectionRenderer가 단순히left = pageLeft + rect.x * zoom,width = rect.width * zoom을 신뢰하기 때문에 native rect 오류가 그대로 화면에 드러난 것으로 보인다.특히 아래 분기 점검 필요:
점검해야 할 사항:
lh와rh가 같은 줄/같은 컨테이너의 커서 hit인지range_end가 줄 끝/비렌더링 문자일 때right_hit가 다음 줄 또는 다른 컨테이너 hit로 잡히지 않는지cell_ctx.is_none()경로에서find_column_area()만 기준으로 삼아야 하는지, 글상자/박스/표 내부 텍스트에서 별도 컨테이너 bbox가 필요한지cell_ctx=Some경로도 셀 bbox로rect_x..rect_x+width클램프가 필요한지예상 해결 방향
Stage 1. 재현/계측
exam_social1.hwp의 오른쪽 박스 텍스트 드래그를 재현한다.hitTestFromEvent결과:sectionIndex,paragraphIndex,charOffset,parentParaIndex,controlIndex,cellIndex,isTextBox,cursorRectgetSelectionRects*()반환 rect 배열:pageIndex,x,y,width,heighthitTestHeaderFooter정정과 무관하게 본 증상이 재현되는지 확인한다.Stage 2. native selection rect 정합화
src/document_core/queries/cursor_nav.rs::get_selection_rects_native를 우선 점검/수정한다.권장 방향:
TextRunbbox와 해당 줄의 컨테이너 bbox를 기준으로 계산한다.lh와rh가 다른 줄/다른 컨테이너에서 온 경우, 줄 끝 rect 계산을 별도로 처리한다.0..page.width,0..page.height로 방어 클램프한다.selection_continues일 때도 무조건 column 끝까지 확장하기보다 현재 줄의 실제 컨테이너 끝을 사용한다.완료 조건:
Stage 3. frontend 드래그 성능 개선
정확도 수정 후에도 버벅임이 남으면
rhwp-studio쪽을 최적화한다.권장 방향:
SelectionRenderer.render()에서 div 전량 삭제/재생성 대신 기존 div pool 재사용.updateCaret()전체를 호출하지 않고, 선택 갱신 전용 경량 경로를 분리하는 방안 검토.scrollCaretIntoView,emitCursorFormatState,updateFieldMarkers호출 빈도 제한.완료 조건:
회귀 테스트 제안
Native/Rust
get_selection_rects_native()에 대해:각 rect에 대해 다음 조건을 검증한다.
x >= 0width > 0x + width <= page_width + epsilonx..x+width가 컨테이너 bbox를 초과하지 않음rhwp-studio e2e
rhwp-studio/e2e/text-selection-drag.test.mjs후보:.selection-layer하이라이트 div들의getBoundingClientRect()수집비목표
본 이슈는 마우스 드래그 텍스트 선택의 rect 정확도와 드래그 중 렌더링 성능에 한정한다.