벡터 직결 10ms 파이프라인 — B. ObjC 벡터렌더러 + 라우팅 단일화 완료
개요
CrownyDoc 2026-07-12-벡터직결-계약.md(SSOT)의 "B. ObjC" 절 5개 항목을
/Users/ef/CrownyBrowser/native/crowny-browser.m (단독 소유 파일) 하나에 구현.
Makefile 변경 없음(신규 소스 파일 추가 안 함).
무엇을 했는지
- CIF v4 글리프 캐시 —
CBGlyphV4(비공개 ivar 클래스, cgPath/em/advance) +
cbParseCIFv4()(M/L/Q/C/Z → CGPath) + cbLoadGlyphV4()(코드포인트→캐시,
딕셔너리, 앱 수명) + cbDrawVectorText()(NFC 정규화 후 문자별
advance×(size/EM) x-전진, 베이스라인=상단+0.8×size — crownyc.c
fb_fill_glyph_v4(opcode807) 규약과 동일). 미존재 글리프는 박스
플레이스홀더(블로킹 생성 없음).
- display list 렌더 경로 —
CrownyAppView클래스 익스텐션에
_displayList[CB_VEC_MAX_CMDS]/_displayCount/_vecCanvasW/H/
_hasDisplayList 추가. parseVectorCmd:(INIT/RECT/ROUND/SHADOW/TEXT/HIT/END
파싱, INIT 못 찾으면 실패로 판정해 자동 폴백), drawVectorDisplayList(CTM
한 번 세팅 후 CG로 순회 드로우: RECT=FillRect, ROUND=CGPathCreateWithRoundedRect,
SHADOW=CGContextSetShadowWithColor, TEXT=cbDrawVectorText, HIT=그리지 않음).
drawRect:가 _hasDisplayList면 PPM(self.rep) 블릿 대신 이 경로 사용.
- termSrv → appSrv 일반화 — 기존 터미널 전용 상주 VM 세션 골격(구
termSrv*/gTermSrv*/kTermSrv*)을 서비스 무관으로 전면 리네임:
kAppSrvSrc()→src/앱상주서버.한선, kAppSrvToau→/tmp/앱상주서버.toau,
appSrvStart/Stop/Request/EnsureToauFresh/FindFreePort, 수명주기 판정을
cbIsVectorService(터미널·계산기) 기준으로 확장(appSrvUpdateForTabChange).
4항 stale mtime 가드 유지. CROWNY_TERMSRV_PORT env 이름은 하위호환을 위해
그대로 유지(A 서버가 실제로 이 이름을 읽음, 실측 확인).
신규 appSrvRequestMulti() — 다중행 CMD 응답 전용 소켓 리더(단일행
appSrvRequest와 별개). 중요 버그 실측·수정: A 서버 응답 와이어가
...END\n\n(본문 자체 trailing \n + TCP쓰기의 +\n으로 개행 2개)로 끝나
naive hasSuffix:@"END\n" 매칭이 항상 실패 → 매 요청 500ms 타임아웃까지
블록되는 치명 함정이었음. trim 후 hasSuffix:@"END"/hasPrefix:@"오류:"로
교정, 실물 서버(포트 19801 수동기동) 대상 왕복 실측 1.6~3.3ms로 확인 후 수정.
- 이벤트→벡터 verb 전송 —
injectKey:(KEY/BS),viewDidMoveToWindow
renderAndReload(렌더, cbIsVectorService면 최상단에서 동기
소켓왕복 시도 후 성공시 즉시 return — 기존 dispatch_async 스폰 파이프라인
완전 우회), mouseDown:(HIT 배열 역순 스캔→매치 시 "액션" 전송) 5곳 모두
"벡터 우선 + 실패 시 기존 스폰/폴백 경로로 자연 낙하" 패턴(sendVectorEvent:arg:
단일 헬퍼로 통일 — 성공 시 표시리스트 갱신+setNeedsDisplay까지 완료).
mouseDown:의 rw/rh 계산도 벡터 모드일 때 _vecCanvasW/H 사용하도록 수정
(기존엔 self.rep 기준이라 벡터 모드에서 배율 오판정 함정이 있었음).
- 라우팅 단일화 — 신규
routeCrownyAppURL:메서드로createTabWithURL
navigateActiveTabTo(기존엔 필터 없이 loadNativeAppURL 직행 — 두 진입점이
서로 다른 판정을 하던 "대충 연결" 버그)를 단일 판정으로 통합. 벡터 지원
서비스(터미널·계산기)만 네이티브 탭 부활, 그 외는 여전히 웹 리다이렉트.
결정기록 주석 삽입.
--selftest-vector [cmd파일경로]CLI 진입점 추가(GUI 불요) — 실물
/tmp/계산기.cmd//tmp/터미널.cmd(A 서버가 실제로 만든 파일)에
parseVectorCmd:를 그대로 돌려 verb 카운트를 로그(오프라인 파서 단위검증).검증 (실행+출력 근거)
clang -fsyntax-only -DCROWNY_VM_WEBKIT -DCROWNY_HYBRID crowny-browser.m→
clang -fsyntax-only -DCROWNY_PRODUCT_CROWNY crowny-browser.m→ 경고 6건
- 두 구성 모두 실제 링크 빌드(Makefile 동일 플래그, 산출물은 스크래치패드에만 —
otool -L로 crownyonly 변종 WebKit 링크 0 확인.
--selftest-vector /tmp/계산기.cmd→ PASS (INIT=1 RECT=1 ROUND=17 SHADOW=17
/tmp/터미널.cmd도 PASS(21 verb, HIT=3).
--selftest-inputv2(기존 회귀 스위트) 19/19 PASS — 회귀 0.- A 서버(
src/앱상주서버.한선→/tmp/앱상주서버.toau)를 포트 19801에 수동
관련 파일
/Users/ef/CrownyBrowser/native/crowny-browser.m(유일 수정 파일, 8071줄)- SSOT:
2026-07-12-벡터직결-계약.md(스크래치패드), 가드레일:
~/.claude/templates/한선씨-가드레일.md
- 검증 스크립트(임시, 스크래치패드):
벡터프로토콜_수동검증.c+
.한선(crownycode-learn 등재: intent=벡터소켓다중행응답대기)잔여 이슈
- 조합(한글 자모, injectJamo) 경로는 이번 벡터 직결 배선에서 제외(계약
- 터미널 스크롤백 클릭(
appAnyHitRect기반 "빈 영역 판정")은 여전히 구
/tmp/히트맵.psv 파일에 의존 — 벡터 전용 경로로만 구동될 때 이 파일이
갱신 안 되면 스크롤백/버튼 클릭 판정이 약간 부정확할 수 있음(크래시/기능
마비 아님, 근사 동작). C(통합) 단계에서 실사용 시나리오로 재확인 권장.
- SHADOW 렌더는 CGContextSetShadowWithColor 근사(정확한 blur 반경 시각 대조는