크라우니 오피스 문서도구 native 배선 3종 (W-B123: B1 DOCX 여백 + B2 변경추적 저자 + B3 PDF WebKit 통일)
개요
크라우니AI 오피스 앱의 native(ObjC) 계층에 남아있던 3가지 잔여 배선을 완료:
- B1: DOCX 내보내기 시 여백/용지가 항상 A4·1417twips 하드코딩이던 것을 사용자가 설정한
- B2: 변경추적(트랙체인지) 저자명이 crownyBridge.js 훅(
window.__crownyOfficeSetAuthor)까지만
- B3: 메뉴 "PDF 내보내기"가 VM 텍스트 PDF(서식 미반영)였던 것을 ⌘P와 동일한 WebKit
createPDFWithConfiguration: 벡터 렌더로 통일(macOS 11+, 실패 시 기존 VM 경로로 fail-open).무엇을 했는지
B1 — DOCX 여백/용지 동적 배선
- 한선씨 엔진(
bundle/office/bridge/내보내기.한선):문서XML조립()이 고정 리터럴 sectPr을
페이지설정꼬리조립()(신규) 호출로 교체. 이 함수가 환경변수()로
CROWNY_OFFICE_PAPER / CROWNY_OFFICE_MARGIN_{TOP,RIGHT,BOTTOM,LEFT}_MM을 읽어
용지트윕스치수(): A4=11906×16838, Letter=12240×15840,mm트윕스(): 반올림(mm * 56.6929))글자수==0)이면 기존 리터럴(A4, 1417twips 4방향, header/footer=708, gutter=0)을
그대로 유지 — 회귀 불변. header/footer/gutter는 이번 배선 범위 밖(고정 유지).
- native(
native/crowny-ai-content.m):caExportOfficeDocumentFormat을 리팩터링 —
finishExport 블록으로 분리하고, docx 모드에서만 kCAOfficePageSetupJS
(⌘P 경로 caPrintOfficeDocument와 동일 소스, §26 노출)를 추가로 읽어 pagesetup JSON을
파싱, 위 5개 환경변수로 변환해 VM 스테이지(caOfficeExportRunVMStage)에 전달.
kCAOfficePageSetupJS 상수는 원래 caExportOfficeDocumentFormat보다 뒤에 선언돼 있어
전방참조 컴파일 에러가 나므로 kCAOfficeExtractJS 옆으로 재배치.B2 — 변경추적 저자 주입
native/crowny-ai-content.m에caInjectOfficeAuthorForWebView:/caOnAccountChangedForOfficeAuthor:
caIsActiveTabOffice 바로 뒤). 로그인 상태([CAAccount shared].loggedIn)
+ username 존재 시에만 window.__crownyOfficeSetAuthor('<이스케이프된 이름>') 호출, 미로그인
이면 호출 생략(기존 '나' 폴백 유지 — 회귀 불변).
- 호출 지점 2곳:
webView:didFinishNavigation:에서 로드 완료된 탭이 오피스 문서(URL 판정은
caIsActiveTabOffice와 동일 기준, 다만 임의 탭이라 인라인 재적용)면 즉시 주입.
2. 계정 변경 알림 — initWithFrame:에 옵저버 등록. 알림 이름은 문자열 리터럴
"crowny.ai.accountChanged"(SSOT=crowny-ai-main.m:55의 CAAccountChangedNotification
상수값 미러 — 그 상수 자체는 extern 선언이 없어 심볼 참조 대신 리터럴로 관찰, main.m 무수정
원칙 준수). 발화 시 모든 탭을 순회해 오피스인 탭 전부에 재주입.
CAContentController (CAOfficeAuthorForward)forward-declare 카테고리를CADocListForward
B3 — 메뉴 PDF WebKit 통일
caExportOfficeDocumentPDF를 완전 재작성:@available(macOS 11.0, *)이면
wv createPDFWithConfiguration:completionHandler: 호출 → 성공 시 그 NSData를
caOfficeDocsDir()에 직접 저장(파일명 규칙은 기존 VM 경로와 동일 —
caSanitizeOfficeTitle(title)-yyyyMMdd-HHmm.pdf).
- 실패 조건(구형 macOS·webView 없음·createPDF 에러·빈 데이터) 전부 기존
caExportOfficeDocumentFormat:@"pdf" ... VM 경로로 fail-open — 그 함수 자체는 무수정.
- 페이지설정 반영은 추가 배선 없이 crownyBridge.js가 이미
<head>에 상주시키는
@page/@media print CSS(§26 buildPageCSS, pagesetup 패널 1회 이상 적용 시 생성)에
의존 — createPDFWithConfiguration:은 WebKit 내부 인쇄 파이프라인을 경유하므로 ⌘P와
동일 CSS 소스를 그대로 공유한다는 것이 이 방식 채택의 핵심 근거(스펙 문서 "소스 이중화 금지").검증 (실측)
- 한선씨 컴파일:
hanseonc_high 내보내기.한선에러 0(경고 0), 46200 큐브 생성. - 한선씨 자체시험:
crownyc run→ PASS 38/38(환경변수 미설정 상태 — 기존 자체시험은
unzip -p out.docx word/document.xml:w:pgSz w:w="11906" w:h="16838" / w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0"
— 기존 하드코딩 리터럴과 완전 일치(회귀 없음 확인).
CROWNY_OFFICE_PAPER=Letter, top=30mm/right=bottom=left=20mm) →w:pgSz w:w="12240" w:h="15840" / w:pgMar w:top="1701" w:right="1134" w:bottom="1134" w:left="1134" w:header="708" w:footer="708" w:gutter="0"
— Letter 표(12240×15840) 정확, 30mm×56.6929=1700.79→1701, 20mm×56.6929=1133.86→1134 정확.
- native 빌드:
make ai에러 0, 경고 4(전부 사전존재 — crowny-ai-main.m ivar 미참조 3건 +
- B2/B3: 정적 코드경로 추적만(실행 앱 미기동 — 아래 "잔여" 참조).
관련 파일
/Users/ef/CrownyBrowser/native/crowny-ai-content.m
crowny-ai-content.m.bak-b123-1784822511)
/Users/ef/CrownyBrowser/bundle/office/bridge/내보내기.한선
내보내기.한선.bak-b123-1784822511)
- 학습:
crownycode-learn.sh add docx_sectpr_동적생성,add twips환산_mm트윕스
잔여·위임 항목
- 실행 앱 반영 미완료:
make ai는native/CrownyAI바이너리만 갱신하고 실행 중인
CrownyAI.app 번들은 교체하지 않는다(CrownyBrowser/CLAUDE.md 경고 항목). 실기동 검증
(B2 로그인 주입/B3 벡터 PDF 육안 확인)은 install-ai-app.sh 실행 + 앱 재시작 이후 —
이 세션은 권한 범위상 설치 스크립트를 실행하지 않았다(메인 세션 권한, 지시사항 준수).
- B2 알림 이름은 문자열 리터럴(
"crowny.ai.accountChanged")로 관찰 —CAAccountChangedNotification
- B3 pagesetup 반영은 가정 기반:
createPDFWithConfiguration:이 WebKit 인쇄 파이프라인을
@page/@media print CSS를 실제로 적용하는지는 Apple 공개 문서에 명시적 보장이 없고,
이 세션에서 GUI 실측(실제 PDF 열어 여백 확인)은 못 했다(위 1번과 동일 사유). 통합 단계에서
pagesetup 터치 후 PDF 내보내기 → Preview.app에서 여백 실측 필요.
- B1의 header/footer/gutter는 이번 배선 범위 밖(708/708/0 고정) — 필요 시 후속 배선.