Repository navigation
Chromium integration: remaining C API and build gaps after the merged compatibility work #520
Description
This tracks the remaining work to replace Chromium's whole HarfBuzz dependency with the standalone HarfRust C API. It updates the Chromium assessment in #468 and links the Skia work in #507.
The buffer, font-callback, set/map, lookup-glyph collection, tag-conversion, MATH, baseline, face-metadata, Unicode-script, and nominal-glyph compatibility work has landed. At the audit snapshot below, the listed APIs were absent from both main and the union of the existing compatibility PRs. Their implementation status is updated here as work proceeds.
Implementation status — 2026-10-08
The 12 originally uncovered metadata functions now have implementation PRs. These checkboxes mean implemented and proposed, not merged. The combined stack now passes the local January Chromium build and runtime smoke checks described below; the newer October audit checkout has not been built.
- OT script selection and feature queries, layout constants, and deprecated MATH flag alias: C API: add OpenType script selection and feature queries #521. CI green. Uses Rust's native binary search; duplicate-script behavior in invalid fonts is not matched.
- Common packed color API independent of paint: C API: expose common colors independently of painting #522. CI green. C API: add optional Skrifa draw and paint features #519 now uses the same core definitions; its updated CI is green.
- CPAL palettes: C API: add OpenType CPAL palette queries #523, stacked on C API: expose common colors independently of painting #522. CI green; 10,093 HarfBuzz comparisons across 497 faces.
- Variation-axis metadata and localized UTF-16 names: C API: expose variation axes and localized UTF-16 names #524, stacked on C API: add OpenType CPAL palette queries #523. CI green; 84,039 palette/axis/name comparisons across 499 faces, including synthetic localized-name and axis fixtures.
- AAT feat-table feature/selector metadata and
hr-hb-aat.h: C API: expose AAT feature and selector metadata #525, stacked on C API: expose variation axes and localized UTF-16 names #524. CI green. 116,180 metadata comparisons across 500 faces. - Optional subset-fuzzer
hb_face_collect_unicodes: capi: collect nominal cmap Unicode coverage #526. CI green; local tests/Clippy/MSRV and C/C++ linkage checks pass. 493 coverage sets match HarfBuzz; two format-13 last-resort faces retain complete ranges where HarfBuzz incorrectly truncates them.
#511–#516 remain open for subsetting, C++ helpers, and integration tests. The Skia UPEM call, Chromium GN/header integration, Unicode/ICU alignment, shaping parity, and landing/integration of the proposed CFF/CFF2 backend stack remain outstanding as listed below. A full browser build against the standalone C API has completed for the available January checkout, with runtime rendering and PDF smoke checks passing. Native GN dependency vendoring, newer-checkout validation, Unicode alignment, shaping parity, and integration/consumer validation of the proposed Skera backend remain open. Combined verification is detailed below.
Proposed Skera CFF/CFF2 backend
CFF/CFF2 subsetting and full/partial CFF2 instancing now have an implementation proposed in Fontations native GitHub stack #2267, in this order:
- googlefonts/fontations#2248: CFF1/CFF2 subsetting, retained subroutines, desubroutinization, hint removal, retained glyph IDs, CID fonts, and
seacclosure. - googlefonts/fontations#2249: Full CFF2 instancing, including metrics and layout variation deltas.
- googlefonts/fontations#2250: Partial instancing and narrowed axis ranges, shared variation stores, and COLRv1 paints.
- googlefonts/fontations#2252: Full CFF2-instance conversion to CID-keyed CFF1.
- googlefonts/fontations#2253: Coupled avar2 partial instancing, hidden pinned axes, and OS/2 style metadata.
- googlefonts/fontations#2254: Self-review fixes for caller-dependent subroutines, shared hint/drawing operands, computed hint calls, and operand provenance.
- googlefonts/fontations#2255: Self-review fixes for wide deltas, recursive feature conditions and GDEF remapping, MATH values, average widths, malformed trees/axes, and unsupported VARC instancing.
- googlefonts/fontations#2263: Review fix for unused class slots in PairPos and all three mark attachment formats, with Skera instancing coverage.
- googlefonts/fontations#2264: Nested CFF2 default/delta expressions in subsetting and full/partial instancing, shared Private DICT rebasing, bounded expression work, and negative half-unit metric rounding.
- googlefonts/fontations#2266: HarfBuzz float normalization, separate outline and runtime-metric coordinates, float variation-store accumulation, and continuous double CFF2 control bounds; fixes the fractional-location outline/metric differences found during review.
All ten PRs pass CI and are verified members of native GitHub stack #2267. The reviewed Skera stack passes 198 unit, ten CFF semantic, and 92 integration tests (300 total; eight existing ignored), and Rust 1.89 Clippy with all features/targets and warnings denied. The class-matrix fix also passes 310 write-fonts unit tests and six doc tests, plus Clippy for both packages. The expanded HarfBuzz differential sweep covers 512 fractional locations per variable font: 11,776 full-instance cases and 237,568 glyph comparisons with exact outlines and metrics. All 27 differences found in the preceding 128-location sweep are fixed. Partial checks cover 222 cases and 67,767 glyph comparisons, including second-stage full instancing. An additional 12 fractional-range cases on Source Serif pass 1,512 glyph comparisons, including defaults at normalized half-unit boundaries. The subset corpus covers 2,304 cases and 175,944 glyph comparisons; 24 source VARC-stub cases cannot be drawn by the independent oracle. OTS accepted ten outputs from the latest revision, including fractional outlines and wide metric deltas, in addition to earlier corpus validation. Nested higher-order partial outlines use the original font as the oracle because HarfBuzz's partial output drops that term.
A deterministic malformed-input run found an HVAR panic that is now fixed and regression-tested; the restarted run completed 8,644,688 cases without another panic. The fresh 30-minute run including nested blends completed 8,233,406 cases without a panic, and a five-minute run against the precision change completed another 1,240,996 cases without a panic. Partial instancing still has coefficient/F2Dot14 quantization limits; exact equivalence at every re-encoded location is not guaranteed.
These PRs are proposed, not merged. HarfRust's subset PRs still need the updated Skera dependency after landing, followed by C API and Chromium Paint Preview validation with CFF/CFF2 inputs. The existing browser/PDF smoke checks below predate this backend stack and do not validate it.
Combined local verification
Locally combined #511–#516, #519, and #521–#527 in an isolated branch and resolved their overlapping modules/header generation. The combined library passes:
- 160 C API tests with all features, plus workspace Clippy with all features/targets.
- 20 GCC/Clang C99 and C++11/C++17 linkage/runtime checks, including C++ subset-header include ordering and rendering consumers.
- 37,987 OT-query and 116,180 palette/axis/name/AAT comparisons against HarfBuzz.
- 79 subset/input/plan differential cases, plus object lifetime, snapshot, preprocessing, and table passthrough checks.
- 2,610 outline/state and 48 paint comparisons.
The initial implementation PRs #521–#526 and the updated #519 passed CI. The additional Chromium source-compatibility fixes in updated #525 and new #527 also pass Linux, macOS, and no-std CI. The full local Chromium GN browser build and runtime smoke checks also pass, as recorded below. The production integration checklist remains open.
Scope and revisions
Audited on 2026-10-08 against:
- HarfRust main
549c33e6. - Chromium
56860caa, including its pinned Skiad058324d. - Open PRs capi: add optional Skera-backed subset feature #511–test: exercise real Skia shaping and PDF subsetting against HarfBuzz #516 and C API: add optional Skrifa draw and paint features #519; their mappings were considered together so pending implementations are not counted as uncovered.
Chromium already enables HAVE_HARFRUST and builds the Rust bridge in its HarfBuzz GN target. This still builds and links HarfBuzz; it does not establish that the standalone C API can replace that target.
Originally uncovered C APIs: 12 functions
| Area | Missing functions | Chromium consumer |
|---|---|---|
| GSUB/GPOS script and feature queries | hb_ot_layout_table_select_script, hb_ot_layout_language_find_feature, hb_ot_layout_table_get_feature_tags |
Small-caps probing, feature enumeration |
| AAT feature metadata | hb_aat_layout_get_feature_types, hb_aat_layout_feature_type_get_selector_infos |
AAT small-caps probing |
| CPAL palettes | hb_ot_color_has_palettes, hb_ot_color_palette_get_count, hb_ot_color_palette_get_flags, hb_ot_color_palette_get_colors |
Palette lookup |
| Variation axes and localized names | hb_ot_var_get_axis_count, hb_ot_var_get_axis_infos, hb_ot_name_get_utf16 |
Axis-name lookup |
#468 excluded palettes and axis names because they construct their own faces outside the shaping-font path. They are still required to remove HarfBuzz entirely. The AAT gap is feature metadata, not a claim that AAT shaping is missing.
Associated types and compatibility constants must also be exposed:
- Layout:
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,HB_OT_TAG_GSUB,HB_OT_TAG_GPOS,HB_OT_TAG_DEFAULT_SCRIPT,HB_OT_TAG_DEFAULT_LANGUAGE. The last two are used by the already-supported baseline path. - AAT:
hb_aat_layout_feature_type_t,hb_aat_layout_feature_selector_t,hb_aat_layout_feature_selector_info_t; feature typesLETTER_CASE,LOWER_CASE,UPPER_CASE; selectorsSMALL_CAPS,LOWER_CASE_SMALL_CAPS,UPPER_CASE_SMALL_CAPS, with theirHB_AAT_LAYOUT_*spellings. - CPAL:
hb_ot_color_palette_flags_tandHB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND/...DARK_BACKGROUND. - Axes:
hb_ot_var_axis_info_tand the name-ID/type definitions required by the exposed signatures. - MATH: Chromium still uses the deprecated spelling
HB_MATH_GLYPH_PART_FLAG_EXTENDER. Add that alias or change the consumer toHB_OT_MATH_GLYPH_PART_FLAG_EXTENDER; the underlying implementation is already merged.
hb_color_t and its four channel getters originally lived in #519's optional paint module/header. #522 and the updated #519 now expose these common definitions through the core compatibility surface, so CPAL users do not need drawing/painting.
Work already covered by open PRs
| PR | Coverage |
|---|---|
| #511 | Skera-backed subset entry points, including Skia PDF's basic subset path |
| #512 | Configurable subset input sets/flags and preprocessing |
| #513 | Plans/maps/object metadata and no-subset table passthrough |
| #514 | hb-cplusplus.hh ownership helpers |
| #515, #516 | C/C++ and Windows integration tests, subset comparisons, actual Skia shaping/PDF tests |
| #519 | Optional Skrifa drawing/painting and common color helpers |
Chromium Paint Preview specifically needs HB_SUBSET_SETS_NO_SUBSET_TABLE_TAG passthrough from #513, not just #511's basic subset API. #513 uses the public Skera Plan API from googlefonts/fontations#2234, now merged; the PR still pins its implementation commit and should move to a released dependency when available.
Consumer, build, and behavioral work
- Resolve Skia's remaining
hb_face_set_upemcall, tracked in Skia integration: remaining HarfRust C API gaps, including PDF subsetting #507. The pinned Skia shaper still calls it. The proposed route is to remove the redundant setter in Skia rather than add an override unsupported by HarfRust's font model. - Wire the standalone C API/subset feature into Chromium's GN build and provide the expected
hb.h,hb-ot.h,hb-aat.h,hb-subset.h, andhb-cplusplus.hhinclude paths. Validate Rust dependencies, linkage, and component-build exports with Chromium's toolchain. - Check opaque-type compatibility at the
hb_set_tforward-declaration/Unretained allowlist, including include order with thehb_set_t→hr_set_tmacro mapping. The local January Chromium build has a concrete consumer: Paint Preview bindsAddGlyphswithbase::Unretained(glyphs). Itshr_set_tallowlist entry is applied in the build experiment; both base-first and HarfBuzz-first header orders pass Chromium's completeness assertion. This is a source/type integration fix. - Establish Chromium Unicode/ICU compatibility; continue Need external ICU callbacks for Chromium integration #360. Having an ICU properties feature does not by itself establish alignment with Chromium's ICU data/version.
- Continue shaping/metrics parity validation, including the measured fractional variation-advance differences in Fractional GPOS variation advances differ at 16.16 scale in Skia #517.
- For
enable_paint_preview, land the proposed Skera CFF/CFF2 stack above, update the HarfRust subset dependency, and validate the C API/Chromium consumer with CFF/CFF2 fonts. Chromium's GN configuration disables CFF subsetting normally and enables it for Paint Preview. The backend implementation is proposed; dependency integration and consumer validation remain pending.
Do not count every vendored HarfBuzz reference as a default Chromium blocker: Chromium builds FreeType with WITHOUT_HARFBUZZ. Its HarfBuzz GN target also disables draw/paint and VARC. Consequently draw/paint and VARC subsetting are not unconditional blockers for this configuration. If enabling the optional subset fuzzer, it additionally needs hb_face_collect_unicodes.
Suggested implementation and verification order
- Add the small constants/aliases and expose common color helpers independently of paint.
- Implement OT script/feature queries, then CPAL palettes, then axis/name queries, then AAT feature metadata, using Fontations table readers where available.
- Land the existing subset/C++ integration stack and resolve the Skia UPEM call.
- Integrate GN and compile Blink, ui/gfx, Skia, and Paint Preview configurations, then attempt a full Chromium build.
- Compare query behavior against HarfBuzz: script/default-language fallback, pagination and returned total counts, palette flags/color ordering, AAT selectors/default indices, localized UTF-16 names and buffer termination. Run shaping, variable-font, MathML, palette, and subset tests in Chromium.
Method: identified 49 existing source/header consumers in the local Chromium checkout, fetched those files at the pinned current Chromium revision, stripped comments, collected bare hb_/HB_ identifiers (including function-pointer uses), filtered against public HarfBuzz header names, and compared against the union of the compatibility headers in the open PR stacks. Also checked Chromium's pinned Skia shaper/PDF sources and GN build flags. This is a scoped source/API audit; it is not a completed standalone-C-API Chromium build or an exhaustive audit of every optional platform target.
Chromium build attempt — 2026-10-08
A complete browser build has succeeded against the available local Chromium checkout, df089deda0ca0195688e416c2cbe84dba9bd48ee (2026-01-07), rather than the newer October audit snapshot. The existing Linux x64 debug component build enables Paint Preview. The experiment replaces the HarfBuzz target with a source-built Cargo C API shared library and compatibility headers, using the locally combined PR stack. It also adds hr_set_t to Chromium's opaque-type Unretained allowlist and applies the Skia UPEM removal locally. Existing build edits were saved and cleaned; the original out/Default Siso build directory is reused, with outputs initially reflinked to out/HarfRust before an aborted plain-Ninja attempt there. That copy is not a pristine binary backup; tracked source edits and original build arguments are backed up separately.
GN generation and the HarfRust target header dependency check pass. The source-built release C API shared library is linked by its libharfrust_c.so SONAME. The Skia, Blink platform, and Blink core libraries have linked with a direct DT_NEEDED entry for this library; the complete chrome target has built successfully (Chromium 145.0.7622.0). Direct compilation with Chromium's generated commands passes for Skia PDF subsetting, Blink face setup, Blink MATH, and Paint Preview subsetting (including its opaque-set callback). The base allowlist header change triggers a broad browser rebuild. This is a local build proof, not yet an upstream-quality native Rust GN dependency integration. CFF/CFF2 subset capability and Unicode/shaping parity remain separate validation work.
Compiler findings from the browser build
- capi: match HarfBuzz C++ source types and constant expressions #527 fixes
hb_buffer_add_latin1's unsigned-byte pointer type, restores boolean/constant-expression direction macros, and preserves unsigned tag/flag/feature-bound literals in the generated core header. The latter fixes a realDCHECK_EQ(HB_TAG_NONE, 0u)signedness error; C++11/C++17 regression checks pass with-Wall -Wextra -Werror. Linux, macOS, and no-std CI pass for the additional constant update. - Updated C API: expose AAT feature and selector metadata #525 preserves unsigned AAT macro constants, required by Blink's templated unsigned feature-vector comparisons.
- Fixed the Cargo/GN experiment to link the Rust C API with Chromium's Clang and Debian sysroot. The initial host-linked library requested
GLIBC_2.33/GLIBC_2.35symbols and failed the V8 snapshot-generator link. The rebuilt library and snapshot generator now link successfully. This was a toolchain integration error, not a missing C API. - Applied local Chromium consumer changes: include the API header in
font_features.h,shape_result.h, andlayout_locale.hinstead of declaring distinct pre-alias HarfBuzz types, and expose the library as a public dependency of Blink's platform target.
The combined library still passes 160 tests and both C++ regression checks. HarfRust and Blink platform header dependency checks pass. Direct Blink shaper, AAT small-caps, and OpenType small-caps compilation now passes. The browser build has resumed with these fixes using 20 local compilation jobs and at most two concurrent links. Roughly 56,000 build steps were reused; about 20,000 affected steps require a broad rebuild. The complete browser build and headless/PDF smoke checks have now passed.
Completed local browser build and runtime checks
- Full Linux x64 debug component
chrometarget built successfully with the combined C API/subset stack. No HarfBuzz source target is built by the experimental replacement. - The executable and checked Skia/Blink libraries import
hr_*functions and nohb_*functions. The executable directly requireslibharfrust_c.so. System FreeType/Pango still bring their independent system HarfBuzz dependency into the process; this does not represent a Chromium shaping fallback. - Headless DevTools checks passed: five explicit web fonts loaded, canvas text measurement succeeded, and screenshot/PDF export succeeded. Visually checked Arabic, Devanagari, Latin ligatures, variable Linefont, two CPAL palettes, and MathML.
- The PDF contains embedded font resources; text extraction preserves the Latin sample. TrueType fonts appear as embedded CID TrueType subsets; Linefont, the color fixture, and Latin Modern Math use Type 3 resources. This does not establish CFF/CFF2 subsetting support.
- CLI
--dump-domcapture timed out for both the smoke page and a blank page in this checkout. The successful smoke tests used direct DevTools navigation/capture instead; the CLI-command timeout remains uninvestigated.
Local binary: /home/behdad/chromium/src/out/Default/chrome. Build recipe, source patch, logs, smoke.png, smoke.pdf, and runtime results are retained under /home/behdad/harfrust/target/chromium-build-review. This proves the local Cargo/GN experiment; it does not finish native GN Rust dependency integration or validate the newer October checkout/all platforms.
Activity