2. 기술 스택

층

c/            Zig 엔진 — pdf.zig 를 중심으로 annot·apply·ccitt·cff·crypt·dest·enc … 주제별 파일
              miniz.c   (DEFLATE)
src/          TypeScript — client·worker·draw·textlayer·annotlayer·viewport·formjs·xfa·sig
              react.ts · vue.ts · svelte.ts   화면 갈래
cmaps/        미리 정의된 CMap — 문서가 실제로 쓰는 이름만 그때그때 받는다
docs/         support.md(무엇까지 되나) · compare.md(pdf.js 와 맞댄 표)
tests/        기능 단언 · pdf.js 화소 비교 · 실문서 대조 · 붙임감(fixture)

엔진은 wasm 하나로 굽고 웹 워커에서 돌린다. 주 스레드는 client.ts 로 워커에 부탁하고 결과를 받아 캔버스에 올린다. Node.js 에서도 같은 wasm 을 돌린다.

메모리를 세지 않는다

9월 1일의 커밋 둘이 이 엔진의 메모리 철학을 보여 준다.

  • 세는 상한을 없앤다 — 표가 문서에 맞춰 늘어난다
  • 안 쓰는 자리는 안 잡는다 — 바닥 메모리 112MB → 38MB

처음엔 객체 표·쪽 표에 상한이 박혀 있었다. 상한을 걷어내면서 malloc 이 엔진 메모리를 밟던 것도 같은 커밋에서 고쳤고, 그다음 필요한 만큼만 잡게 바꿨다. 맨 위 표는 옮기지 않고 뒤로 늘리고, 늘어나는 표는 Table(T) 하나로 접었다(SSOT). 거듭 열어도 메모리가 안 자라는지 보는 테스트가 9월 14일에 붙었다.

색을 제대로 옮긴다

9월 2일에 ICC 색 프로파일을 읽기 시작했다. 그 전에는 53/255 로 나오던 값이 0.8 로 맞아떨어졌다. 색차를 늘릴 때 네 이웃을 섞어 libjpeg 과 5 안으로 맞췄고, /CalRGB 와 16비트 그림, 무색 무늬(/PaintType 2) 의 색까지 챙겼다. 판정은 pdf.js 와 화소를 맞대는 시험이다 — 타일 무늬 간격과 그림 키울 때 뭉개기가 그 시험에서 잡혔다.

양식이 산다

관공서 양식은 문서 안에 JavaScript 를 품고 있다 — 칸을 채우면 다른 칸이 계산되고, 조건에 따라 숨는다. 9월 2일에 문서가 준 JavaScript 를 자체 해석기(jsmini.ts)로 돌리게 했다. 해석기는 "실제 양식이 쓰는 만큼" 만 넓혔다 — 15개 중 7개에서 15개로. 동적 XFA(흐름 배치·자료만큼 되풀이·쪽 나눔·셈하는 칸)도 같은 날 들어갔다.

글꼴

박힌 글꼴은 브라우저가 거절하는 경우가 있어 표를 기워서 다시 낸다. 박히지 않은 표준 14종은 시스템 글꼴로 대신 그리는데 OS·브라우저마다 자리가 다르다 — 같은 글의 serif 폭이 chromium 241 · firefox 273 · webkit 241 로 갈렸다. 그래서 진짜 글꼴을 두고 주소를 알려 주면 그 차이가 없어지게 했고(9/8), 문서가 실제로 쓰는 한 벌만 받는다. 표준 14종의 자간은 AFM 폭 표로 정확히 맞춘다(8/31).

Times·Courier·Symbol 은 Type1(.pfb)뿐인데 브라우저 셋 다 거부한다고 README 가 적어 뒀다 — chromium·firefox·webkit 에 직접 물어본 결과다.

검증

  • 기능 단언 — 9월 26일 확인한 검증 스크립트는 최소 434개를 요구한다. docs/support.md에 남은 397개 표기는 현재 스크립트와 다르다
  • pdf.js 화소 비교 — docs/compare.md, 크게 다른 것은 tests/pdfjs-known.json 에 까닭과 함께
  • 실문서 텍스트·그리기 대조 — 9월 22일에는 문서 100편에서 pymupdf·pdf.js와 비교했다. 개발 과정의 해당 절에 표본과 측정 규칙을 정리했다
  • 퍼저 — 첫 커밋의 wasm32 넘침을 잡은 것이 무작위 퍼저(r8)다
  • 환경이 깨진 자리 열세 가지 — 9월 1일에 두들기다 셋을 고쳤다
  • 빈틈 견본에서 회귀 시험으로 — 9월 5일에는 미지원 기능 여섯을 견본으로 남겼다. 현재 검증 스크립트에는 그 여섯을 구현해 일반 시험으로 옮겼고 빈틈 견본은 0개라고 기록돼 있다. 이것이 모든 PDF 기능의 구현 완료를 뜻하지는 않는다