fontations 0.0.1
fontations: ^0.0.1 copied to clipboard
Flutter bindings for the fontations font stack (read-fonts / skrifa), powered by flutter_rust_bridge.
Unreleased #
Web #
- The plugin declares the web platform and compiles the crate to WebAssembly:
scripts/build_web.shbuildspkg/fontations.js+pkg/fontations_bg.wasm(nightly,-Z build-std, shared memory) and the example app builds and runs on the web.initFontations()and the rest of the API are unchanged. lib/fontations_web.dartis the (empty) web entry point Flutter requires, andflutter_web_pluginsis now a dependency for it.scripts/coop_server.pyserves a build with the cross origin isolation headers a threaded wasm module needs; without themSharedArrayBufferis missing and the worker pool panics at start up.- Fix: the example could not be run at all.
flutter run -d chromeand every plain static host send noCOOP/COEP, so the module panicked withSharedArrayBuffer transfer requires self.crossOriginIsolatedright after loading.example/web/coi_serviceworker.jsnow adds those headers to the navigation response,example/web/index.htmlregisters it and reloads once, andexample/web/flutter_bootstrap.jskeeps Flutter's own service worker unregistered (one scope, one worker - Flutter's would evict this one). Any static server can now host the build;scripts/coop_server.pystays for hosts that can send the headers themselves. - Web has to be built separately - unlike every other platform it is not wired into the platform build systems.
- Tests: the package gained
test/fontations_test.dart(VM only; a browser run needs both thepkg/files and the isolation headers, which theflutter test --platform chromeharness does not provide), and CI gained awebjob pluscargo build --release && flutter testin thedartjob.
Shaping fixes #
USE_MARK_FILTERING_SETis honoured: a lookup that names one takes its "is this a mark?" answer from thatGDEFcoverage table instead of the glyph classes. Previously the flag was parsed and ignored, so a font that filters marks had them treated as bases.- A ligature no longer reaches across a glyph the lookup ignores: every glyph of the sequence is checked, not just the first one.
- Cursive attachment no longer writes its cross stream correction into
y_advance. It belongs iny_offset;y_advanceis vertical layout and used to move every following glyph of a vertical run. - The mark attachment lookups (mark to base / ligature / mark) now respect the lookup flags too; they used to skip them entirely.
- Tests: eight new cases cover multiple, alternate, ligature, contextual,
mark to base and cursive substitution, plus regression tests for each fix
above. They splice the layout tables into a font with
FontBuilder, which is the only way to exercise lookups the write side cannot produce.
CI #
- Added
.github/workflows/ci.yml:cargo fmt --check+cargo teston Linux,dart format+flutter analyzeon Linux, an artifact freshness check, and the example's macOS integration tests. scripts/build_xcframework.shnow records a fingerprint ofrust/inscripts/xcframework.sha256, and the newscripts/check_xcframework.shcompares it against the current crate. A stale prebuilt binary does not fail a build — SwiftPM links it silently — so CI fails on it instead. The macOS job is gated on this check, otherwise its tests could report on Rust code that is not the commit under test.
Packaging #
- Added Swift Package Manager support for iOS and macOS
(
ios/fontations/Package.swift,macos/fontations/Package.swift). Apps that use SwiftPM now link a prebuilt binary (fontations.xcframeworkin each folder) instead of compiling Rust during the Xcode build, because SwiftPM has no script phases and its build tool plugins are sandboxed. The binaries are committed and rebuilt with./scripts/build_xcframework.sh. - The CocoaPods integration still compiles Rust from source as before, and is used automatically by apps that have SwiftPM turned off.
initFontations()now resolves the Rust library in whichever shape it was built into the app: dynamically from the app bundle on SwiftPM, or from the app executable when CocoaPods linked Rust statically.
Write side #
GlyphSpec.componentsbuilds composite glyphs (translated, uniformly scaled parts reused from other glyphs), with the composite bounding box computed from the parts.FontBuildRequest.ligatureswritesGSUBligature substitutions, andmodifyFontcan add them to an existing font.GlyphSpec.colorLayers+FontBuildRequest.palettewriteCOLRversion 0 andCPAL, soFont.colorGlyph/ColorGlyphInfo.paintcan draw them.VariationAxisSpec.mappingswrites anavartable, and the same mapping is applied togvar/HVAR/MVARdeltas so they stay consistent.VariationMaster.globalMetricswritesMVAR(hasc,hdsc,hlgp,hcla), so global metrics interpolate along the axes.FontBuildRequest.verticalMetricswritesvhea+vmtx, with per glyphverticalAdvance/verticalOrigin.FontBuildRequest.rawTablescopies tables verbatim (fpgm,prep,cvt,gasp, …) andGlyphSpec.instructionsstores per glyph TrueType hinting bytecode inglyf.FontBuildRequest.variationSelectorswritescmapformat 14.modifyFontpatches an existing font (metadata,kernPairs, alternates, ligatures) while copying every other table over untouched.OS/2is filled in properly (weight/width class,fsSelectionfrom the subfamily name, vendor id, average width, unicode ranges) and thenametable can carry designer, license, manufacturer and version.kernPairscompile into aGPOSkernfeature;STATis written for variable fonts;StylisticAlternate.namebecomes anssNN/cvNNfeature parameter.- Still open: CFF/CFF2 output,
sbix/CBDT,VORG,COLRv1 andgvaron composites.
Read side #
- Raw access to any table (
Font.tableData/tableLength/hasTable) plus a structured view ofGSUB/GPOS(Font.layout: scripts, languages, features, lookup counts). Font.attributes()(weight / stretch / style fromOS/2),Font.glyphName()+glyphNameSource(),Font.nameRecords({nameId})with every localization,Font.charmapInfo()/charMappings()/glyphToChar().Font.glyphMetrics()(advance, left side bearing, bounds), vertical metrics fromvhea/vmtx/VORG.COLRcolor glyphs flattened into layers (Font.colorGlyph,colorPalettes) with aColorGlyphInfo.paint(canvas)helper on the Dart side, and embedded bitmaps (Font.bitmapStrikes,Font.bitmapGlyph) decoded to RGBA.Font.outline(..., hinted: true)applies the hinting in the font, andGlyphOutlinenow reportsformat,hasHintingandhasOverlaps;Font.outlineFormat()says whether outlines come fromglyfor CFF.Font.shape(text, {size, variations, script, language, features})appliesGSUBandGPOSinstead of only describing them: single, multiple, alternate and ligature substitutions, reverse chains, and the contextual and chained contextual lookups (with their nested lookups); single, pair, cursive, mark-to-base, mark-to-ligature and mark-to-mark positions. Returns advances, offsets and the source cluster of every glyph.MATH:Font.hasMath(),mathConstants({ppem}),mathGlyphInfo(...)andmathVariants(...)expose the constants, the per glyph italics correction, accent attachment and corner kerns, and the variants and assembly of a stretchy delimiter.VARC:Font.hasVarc()andvarcComponents(...)resolve a variable composite glyph into the components it is drawn from, with their transforms, axis values and whether their condition holds at the location.cmapformat 14:Font.mapVariant(codePoint, selector)andFont.variantMappings()look up variation selectors.avar/avar2:Font.avarInfo()reports the per axis segment maps and whetheravar2deltas are present;Font.normalizedCoords(variations)reports the normalized coordinate a set of user settings ends up at.Font.shapetakesfeaturesas a list that distinguishes "unset" from "empty":nulluses the defaults,[]turns every feature off.
Example #
- New shaping page (
example/lib/shaping_page.dart): shapes a run of text withFont.shape, draws the positioned glyphs on a canvas, and lets you toggle every feature the font declares (default / all off / custom). - The font info page now also shows
attributes(), theGSUB/GPOSfeature lists, thecmapsummary, the liveavar-normalized coordinates next to the axis sliders, and which optional tables the font carries (MATH,VARC,COLR, bitmaps, vertical metrics,cmap14). - Shared demo widgets live in
example/lib/demo_widgets.dart. - The example no longer hardcodes its font:
example/lib/font_source.dartholds the open font, the reading and shaping pages both follow it, and the reading page can open any.ttf/.otf/.ttc/.otcthrough a native open panel (file_picker). A.ttccollection gets a face selector, the files opened in a session can be switched between, and the bundledInteris one button away. The preview text is editable, so a font that is not Latin can still be inspected. - The example is now responsive: at 900px and above the shell swaps the
bottom
NavigationBarfor aNavigationRail(labels appear from 1240px) and the read/shaping pages split into two columns, so a desktop window is not one very wide single column. The writing page keeps its board + panel split but caps the panel at 560px. The macOS window opens at 1180×820 with a 640×720 minimum. - Tests: 32 Rust unit tests and 15 Flutter integration tests.
0.0.1 #
- Initial release: exposes the fontations
font stack (
read-fonts/skrifa) to Flutter viaflutter_rust_bridge.Font.fromBytesto parse a font or a single face of a.ttccollection.Font.info/readFontInfofornametable strings, metrics,fvaraxes, named instances and the table directory.Font.charToGlyph,Font.advanceWidthandFont.outlinefor glyph level access, including variable font locations.GlyphOutline.toPath()helper that turns outlines into adart:uiPath.buildFontcompiles glyph contours (in font units) into a.ttfusingwrite-fonts, coveringhead/hhea/maxp/hmtx/OS/2/glyf/loca/name/cmap/post.buildFontalso writes variable fonts: declareaxes(plus optionalinstances) and give each glyphmasters— alternative outlines pinned to points in variation space — to getfvar+gvar. Masters must be point compatible with the default outline.buildFontalso writes stylistic sets:StylisticAlternateentries become extra glyphs reachable throughGSUBsingle substitutions (ss01..ss20,cv01, ...). Each alternate carries its own advance width.- Example app gained a second page: draw a character on a board, bind it to a
code point, save several masters along a
wghtaxis plus discrete variants underss01..ss20, export the font and render it throughFontLoader, with a live interpolation preview and per-feature previews.