Task #1211: rhwp-studio 입력 편집 재렌더 비용 축소#1212
Merged
Merged
Conversation
edwardkim
added a commit
that referenced
this pull request
Jun 1, 2026
@postmelee. npm test 52 passed, Rust 무변경(WASM 불요), narrow invalidation 보수적 화이트리스트. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Owner
|
머지했습니다(devel
검증: rhwp-studio #1207 로 커서가 중첩 셀에 정확히 남으면서 드러난 입력 비용을 이 PR 이 이어서 줄여준 흐름도 좋았습니다. 감사합니다. |
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.
Summary
Related: #1211
rhwp-studio에서 표 셀 내부 텍스트 입력이 매 키 입력마다document-changed -> CanvasView.refreshPages()full refresh를 타며 visible page 전체 재렌더와 image retry state reset을 반복하던 비용을 줄입니다.이번 PR은
samples/exam_social.hwp의성명칸처럼 표 셀 내부에서 발생하는 단일insertText/deleteText편집과 한글 IME 조합 중 raw 텍스트 편집을 좁은 invalidation 경로로 보냅니다. 본문 문단 입력, 붙여넣기, 문단 분할/병합, 객체/표/페이지 구조 변경은 기존 full refresh 경로를 유지합니다.범위
이 PR은 모든 텍스트 입력 경로를 최적화하지 않습니다. narrow invalidation 경로는 보수적으로 page-local 편집이라고 판단할 수 있는 경우에만 사용합니다.
cellPath안에 머무르는 편집insertText/deleteText본문 문단 입력, 붙여넣기, 문단 분할/병합, 표/객체/페이지 구조 변경, header/footer, footnote 편집은 기존 full refresh 경로를 유지합니다.
선택안: 후보 A + C
이슈 #1211의 개선 후보 중 A + C를 선택했습니다.
document-page-invalidated이벤트를 추가해 구조 변경용document-changed와 의미를 분리했습니다.refreshPages()를 호출하지 않으므로, full refresh에 포함된resetImageRetryState()도 매 입력마다 반복하지 않습니다.후보 A를 선택한 이유는
document-changed가 현재 구조 변경과 단순 입력 편집을 모두 대표하면서 full refresh를 강제하기 때문입니다. 이벤트 의미를 분리하면 구조 변경성 작업은 기존 안전한 경로에 남겨두고, 입력 편집만 더 좁은 repaint로 처리할 수 있습니다.후보 C를 함께 적용한 이유는 단순 텍스트 입력이 이미지 payload/topology를 바꾸지 않기 때문입니다. 기존 full refresh는 입력마다 image retry state를 초기화해 이미지가 있는 페이지에서 재시도 예약과 prefetch 비용이 반복될 수 있었습니다.
후보 B처럼
document-changed에 reason을 붙여 내부 분기하는 방식은 기존 이벤트 계약이 계속 모호해질 수 있어 제외했습니다. 후보 D의 flow image 전용 WASM API는 API 표면을 늘리는 작업이므로, A+C 적용 후에도 병목이 남을 때 후속 이슈로 다루는 편이 낫다고 판단했습니다.#865와의 관계
PR #865의
getPageOverlayImages는 overlay 이미지 목록과imageCount만 필요할 때 대형PageLayerTreeJSON을 받지 않도록 하는 최적화입니다. 현재PageRenderer.getOverlayImages()도 해당 API를 우선 사용하므로 overlay 추출 비용은 이미 줄어든 상태입니다.이번 PR은 그 최적화와 별개로 남아 있던 비용을 줄입니다. 즉, 문제의 본질은
getPageOverlayImages부재가 아니라 일반 텍스트 입력까지document-changed -> refreshPages() -> releaseAllRenderedPages() -> resetImageRetryState()full refresh를 매번 타는 점입니다.Changes
CanvasViewdocument-page-invalidated이벤트 처리 추가renderCanvas()분리InputHandlerDocumentPosition을 비교cellPath에 남아 있는 단일insertText/deleteText만 page-local refresh로 라우팅InputHandlerTextinsertTextAtRaw()/deleteTextAt()후afterEdit()full refresh를 직접 호출하지 않고afterTextInputEdit()를 사용Tests
input-edit-invalidationhelper 단위 테스트 추가Validation
수동 확인:
성명칸에테스트입력 확인Measurement
임시 계측 코드를 로컬 worktree에만 넣어 비교했습니다. 계측 코드는 PR 소스에 포함하지 않았습니다.
환경:
puppeteer-coreupstream/devel(c884205d)task-1211(b47f4f4)samples/exam_social.hwp성명셀1280x900, UI zoom140%가나다라마바사아자차10자EventBus.emit,CanvasView.refreshPages(),CanvasView.refreshInvalidatedPage(),PageRenderer.renderPage(),PageRenderer.resetImageRetryState()측정 절차:
/private/tmp/rhwp-measure-beforeworktree에서upstream/devel을 Vite dev server로 실행 (127.0.0.1:7711)/private/tmp/rhwp-measure-afterworktree에서 이 PR branch를 Vite dev server로 실행 (127.0.0.1:7712)rhwp-studio화면으로/?url=/samples/exam_social.hwp&filename=exam_social.hwp를 로드성명셀을 클릭page.keyboard.type()로 10자 문자열을 입력하고 같은 과정을 5회 반복PageRenderer.renderPage()호출 수와 누적 시간을 수집document-changedeventsdocument-page-invalidatedeventsCanvasView.refreshPages()CanvasView.refreshInvalidatedPage()resetImageRetryState()PageRenderer.renderPage()callsPageRenderer.renderPage()total avgPageRenderer.renderPage()total p95scripted input elapsed는 puppeteer typing delay와 fixed wait를 포함하므로 보조 지표입니다. PR의 핵심 개선값은 full refresh / image retry reset 제거와 renderPage 누적 시간 감소입니다.주의: 이 측정은 함수만 직접 호출한 microbenchmark가 아니라 실제 dev server와 browser input을 사용한 end-to-end 경로 측정입니다. 다만 headless Chrome의 scripted keyboard input은 macOS 네이티브 한글 IME 조합 입력과 완전히 동일하지 않을 수 있으므로, 사용자 체감 시간 자체보다 render/invalidation 경로 변화와 렌더 누적 시간 감소를 주 근거로 봅니다.