Skip to content

Chromium integration: remaining C API and build gaps after the merged compatibility work #520

Open

Description

@behdad

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.

#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 seac closure.
  • 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:

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 types LETTER_CASE, LOWER_CASE, UPPER_CASE; selectors SMALL_CAPS, LOWER_CASE_SMALL_CAPS, UPPER_CASE_SMALL_CAPS, with their HB_AAT_LAYOUT_* spellings.
  • CPAL: hb_ot_color_palette_flags_t and HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND / ...DARK_BACKGROUND.
  • Axes: hb_ot_var_axis_info_t and 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 to HB_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_upem call, 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, and hb-cplusplus.hh include paths. Validate Rust dependencies, linkage, and component-build exports with Chromium's toolchain.
  • Check opaque-type compatibility at the hb_set_t forward-declaration/Unretained allowlist, including include order with the hb_set_t → hr_set_t macro mapping. The local January Chromium build has a concrete consumer: Paint Preview binds AddGlyphs with base::Unretained(glyphs). Its hr_set_t allowlist 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

  1. Add the small constants/aliases and expose common color helpers independently of paint.
  2. Implement OT script/feature queries, then CPAL palettes, then axis/name queries, then AAT feature metadata, using Fontations table readers where available.
  3. Land the existing subset/C++ integration stack and resolve the Skia UPEM call.
  4. Integrate GN and compile Blink, ui/gfx, Skia, and Paint Preview configurations, then attempt a full Chromium build.
  5. 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 real DCHECK_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.35 symbols 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, and layout_locale.h instead 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 chrome target 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 no hb_* functions. The executable directly requires libharfrust_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-dom capture 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

  1. self-assigned this
    on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions