AX notes · Measurement

Building an Android HWP viewer: rhwp in a WebView, measured on 222 documents

Running the open-source rhwp engine inside an Android WebView, 221 of 222 Korean HWP and HWPX files opened on a Galaxy S21, with a median of 1.2 to 1.5 seconds from tap to first page.

By SugarMount Android development 8 min read Last updated

221 of 222 Korean word-processor files opened. Before writing HWP Viewer SugarDoc, we wanted to know whether the engine could carry an app at all, so on October 3, 2026 we opened every file from a cold start on a Galaxy S21 (Android 15, WebView 153). The engine passed, with two catches. Drawing every page of a 384-page file pushed the WebView renderer to 2.8 GB, and the set the first report called "24 government documents" held only 17 real government attachments.

Numbers come from the engine spike report in SugarMount's app repository (sugar-utils; measured 2026-10-03, commit 7b0e567), the follow-up verification report (2026-10-05), and a recount from the raw result JSON done while writing this note. Checked on October 19, 2026.

Contents (8)
  1. HWP, HWPX and why a viewer is hard
  2. Setup: one phone, 222 files, a cold start each time
  3. Results: 221 of 222 opened
  4. A 384-page file only works if you draw the visible pages
  5. Fonts went from 144 MB to 9.2 MB
  6. What the AI got wrong, and what verification changed
  7. Still open
  8. FAQ

HWP, HWPX and why a viewer is hard

HWP is the file format of Hancom Office Hangul, the word processor that Korean government offices, schools and many employers still use. HWP 5 is a binary compound file; HWPX is the newer ZIP-and-XML version; very old files are HWP 3.0. On a phone they usually arrive as attachments in KakaoTalk (Korea's main messenger) or email.

Layout is the hard part. Government press releases lean on dense tables, logos and fixed line breaks, and exam papers add equations and two-column pages.

Setup: one phone, 222 files, a cold start each time

rhwp is an open-source HWP/HWPX parser written in Rust and compiled to WebAssembly. It renders each page as SVG and is MIT-licensed. We used the npm package @rhwp/core 0.8.6, and the shipped app is still pinned to that version.

The test app was a single WebView with rhwp and the font stylesheet rhwp ships (153 font rules). For every file the app was force-stopped and relaunched; the first three pages went into the DOM and the rest were only timed.

We had no low-end phone.

Results: 221 of 222 opened

"Tap to first page" is app launch time plus first-page render time, so it includes the cold start. p90 is the value where the slowest 10% begin. Renderer memory is the PSS (proportional set size: private memory plus a fair share of shared pages) of the WebView renderer process.

Metrickorea.kr, 17 filesFirst report's "24 government documents"rhwp samples, 198
Opened17/1724/24197/198
Tap to first page, median1.4 s1.5 s1.2 s
Tap to first page, p901.6 s2.1 s1.9 s
Tap to first page, max1.8 s3.0 s3.3 s
Render per page, median-10 ms6 ms
Renderer memory (PSS), max286 MB391 MB422 MB

The one failure, issue2063_huge_cellbreak_table.hwp, is a stress test built around a giant table split across pages; it ran past the 120-second limit. The spike report made a fallback path a condition for adopting the engine, and the app now lets you keep waiting or hand the file to another app after 10 seconds.

Fidelity held up. Against the reference PDFs, page counts matched for 195 of 197 samples (the other two were one page off), and the median first-page image similarity was 0.997. We also put seven files (two press releases, five samples) side by side with Hancom's output. The press-release tables, logos and bold text and the exam paper's equations and two columns looked nearly the same. The one visible miss was the first question number, "문1)", dropped from one exam paper.

A 384-page file only works if you draw the visible pages

One rhwp sample is a 384-page government administration handbook (10.7 MB). With every page's SVG in the DOM, the WebView renderer process grew to 2.8 GB. Drawing only the visible pages, the same file sat at 255 MB in one run and 366 MB in another run the same afternoon.

Comparison: drawing all pages of a 384-page file took the WebView renderer to 2.8 GB; drawing only the visible pages kept it at 255 MB (366 MB in another run).
Virtual scrolling cut renderer memory by an order of magnitude on the 384-page file.

If you build an HWP viewer on a WebView, put virtual scrolling (only the visible pages and their neighbours in the DOM) in from day one.

The shipped viewer gives every page an empty slot of the right size and keeps SVG only for the visible pages plus two on each side, or one on each side on low-memory devices. Rendered SVG strings live in a byte-capped LRU (least recently used) cache, so the pages viewed longest ago are dropped first.

Fonts went from 144 MB to 9.2 MB

The font folder that comes with rhwp is 87 files and 144,327,972 bytes. The spike report called it "138 MB", which is the same number counted in mebibytes. The 222 documents actually used 17 of those files, about 37 MB.

The app ships 10 files, 9,207,952 bytes, about 6% of the original. Two rules decided what went in: a clear license and a close look. Hancom's own Hamchorom fonts were left out because Hancom's license page does not spell out whether they may be bundled in an app; Hamchorom Batang is drawn with Noto Serif KR and Hamchorom Dotum with NanumGothic, both under the SIL Open Font License. rhwp's NanumGothic was a subset that kept the reserved font name, so we swapped in the original TTF from google/fonts.

Bar chart: rhwp's 87 font files total 144 MB, the 17 the 222 documents used are about 37 MB, and the 10 bundled in the app are 9.2 MB.
The app bundles 10 fonts with clear licenses, about 6% of what rhwp ships.

On 2026-10-05 we measured the cost on the same S21: how much first-page ink overlap (F1) against the reference drops with the substitute fonts. The pass mark, fixed in advance, was a median drop of 0.02 or less; the median came out at 0.0071. One file went over at 0.0336, a college entrance exam (Suneung) paper whose title is in Chinese characters (hanja). The difference sat in the hanja title and the circled numbers ① to ⑤, which the bundled fonts lack, so the system font draws them.

What the AI got wrong, and what verification changed

An AI coding agent (Claude) session ran the engine spike and wrote its report. Two days later, the follow-up experiments split the work: one agent measured, a separate verifier agent reopened the evidence files and recomputed every number, and only corrected values went into the docs. The first report's statistics were recounted at that point.

First reportAfter verification
24 real government documents17 korea.kr files (14 press releases) plus 7 others: 4 byte-identical to samples, 3 rhwp test fixtures
Samples: 177 HWP, 21 HWPX180 HWP, 18 HWPX (9 of them HWP 3.0)
Number recall around 0.9A bug in the comparison script: text runs were joined with no separator, so 11:00 and 10. 2. became 11:0010. 2.. Fixed, all 17 korea.kr files score 1.0 (a lenient upper bound)
Bundled fonts 9,700 KB (the follow-up's measuring agent)KiB written as KB; 9,933,636 bytes is 9.93 MB (later cut to 9,207,952 bytes)

"24 of 24 government documents" reads well, and 7 of the 24 were not government documents. Counted alone, the 17 real files were faster (1.4 s median) and lighter (286 MB max). The engine decision did not change, but without the verifier we would have published a number with the wrong provenance.

Writing this note, we recomputed the medians once more from the raw s21b.json. The report's 1.5, 2.1 and 3.0 seconds came out exactly; the 366 MB run of the 384-page file turned up then. (The verification report also flagged that another script had overwritten one raw file, which must be regenerated before anyone quotes it.)

Still open

FAQ

Can rhwp be used in a commercial Android app?

Yes. rhwp is MIT-licensed, but the Rust crates compiled into its WASM (Apache-2.0, BSD and others) need their notices too. The fonts it ships carry their own licenses and need checking file by file. HWP Viewer SugarDoc bundles 10 font files with confirmed licenses, OFL and others, and leaves out Hamchorom.

Why does a WebView HWP viewer use so much memory?

Every rendered page stays in the DOM as SVG. A 384-page file took the renderer to 2.8 GB with all pages drawn and 255 MB with only the visible ones.

Does one engine open both HWP and HWPX?

Yes. rhwp 0.8.6 opens both, and 221 of the 222 mixed files here opened. The difference between the two formats is explained in HWP vs HWPX: what differs and how to open both. If an HWPX file from a chat app will not open on your phone, see How to open an HWPX or HWP file on Android.

This note is written from values SugarMount measured itself; an AI coding agent was used to draft it.

All notes on Android development · All AX notes