Skip to content

Add color font palette support to C API#197

Merged
mattleibow merged 13 commits into
skiasharpfrom
dev/font-enhancements
Apr 26, 2026
Merged

Add color font palette support to C API#197
mattleibow merged 13 commits into
skiasharpfrom
dev/font-enhancements

Conversation

@mattleibow

@mattleibow mattleibow commented Apr 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extends the variable font C API (merged in #185) with color palette support, enabling SkiaSharp to clone typefaces with specific palette selections and per-color overrides for COLRv1/COLR fonts.

Companion PR: mono/SkiaSharp#3742

Changes

New struct

  • sk_fontarguments_palette_override_t — maps to SkFontArguments::Palette::Override with index (uint16_t) and color (sk_color_t) fields

Extended function

  • sk_typeface_clone_with_arguments — extended from 4 to 7 parameters:
    • paletteIndex — select a built-in palette by index
    • paletteOverrides — pointer to array of color overrides
    • paletteOverrideCount — number of overrides

Type mapping (sk_types_priv.h)

  • DEF_MAP(SkFontArguments::Palette::Override, sk_fontarguments_palette_override_t, PaletteOverride) — layout-compatible, uses reinterpret_cast
  • AsSkFontArguments helper updated to call setPalette() with the new parameters

ABI verification (sk_structs.cpp)

  • static_assert for sk_fontarguments_palette_override_t size matching SkFontArguments::Palette::Override

Files changed

File Change
include/c/sk_typeface.h New struct + extended function signature
src/c/sk_typeface.cpp Updated clone implementation
src/c/sk_types_priv.h DEF_MAP + updated AsSkFontArguments helper
src/c/sk_structs.cpp static_assert for palette override

ramezgerges and others added 7 commits April 19, 2026 18:30
Expose SkTypeface variable font functionality through the C API:
- sk_typeface_get_variation_design_position: query current axis coordinates
- sk_typeface_get_variation_design_parameters: query axis metadata (tag, min, default, max, hidden)
- sk_typeface_clone_with_arguments: create typeface clone with specific variation coordinates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace reinterpret_cast between C and C++ structs with field-by-field
copy. The structs have identical layout so the cast worked in practice,
but accessing memory through an unrelated type is undefined behavior
per the C++ standard. Compilers optimize the copy loop to the same code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add sk_fourbytetag_t typedef (uint32_t) matching SkFourByteTag
- Use sk_fourbytetag_t in variation axis/coordinate C structs
- Add AsVariationPositionCoordinate/ToVariationPositionCoordinate for
  layout-compatible Coordinate struct (verified by static_assert)
- Add ToVariationAxis for Axis conversion (handles isHidden() getter)
- Add AsSkFontArguments helper for clone_with_arguments
- Simplify sk_typeface.cpp: remove manual copy loops, use reinterpret_cast
  for coordinates, use helpers for parameters and font arguments

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace manual reinterpret_cast functions with DEF_MAP macro for
  VariationPosition::Coordinate (generates As*/To* automatically)
- Move static_assert to sk_structs.cpp following existing pattern
- Use AsVariationPositionCoordinate() in sk_typeface.cpp instead
  of inline reinterpret_cast

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add sk_fontarguments_palette_override_t struct
- Extend sk_typeface_clone_with_arguments with palette parameters
- Add DEF_MAP for Palette::Override (layout-compatible)
- Add static_assert for Palette::Override size check
- Update AsSkFontArguments to pass palette through

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace manual reinterpret_cast functions with DEF_MAP macro for
  VariationPosition::Coordinate (generates As*/To* automatically)
- Move static_assert to sk_structs.cpp following existing pattern
- Use AsVariationPositionCoordinate() in sk_typeface.cpp instead
  of inline reinterpret_cast

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mattleibow and others added 6 commits April 25, 2026 23:00
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The generator reads harfbuzz headers to produce HarfBuzzApi.generated.cs.
It needs the 2.8.2 headers (63e15eac) not the build-time version. The
build-time harfbuzz version is controlled separately by the native build.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-enhancements

# Conflicts:
#	include/c/sk_typeface.h
#	src/c/sk_structs.cpp
#	src/c/sk_typeface.cpp
#	src/c/sk_types_priv.h

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the Skia C typeface/variable-font API to support OpenType color palettes by introducing a palette override struct and plumbing palette selection/overrides through the typeface cloning API.

Changes:

  • Added sk_fontarguments_palette_override_t to represent CPAL entry overrides (index + color).
  • Extended sk_typeface_clone_with_arguments to accept palette index and override list/count.
  • Added C↔C++ struct mapping and ABI size static-asserts for the new palette override type.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/c/sk_types_priv.h Adds DEF_MAP for SkFontArguments::Palette::Override and extends AsSkFontArguments to set palette arguments.
src/c/sk_typeface.cpp Updates sk_typeface_clone_with_arguments implementation to pass palette args into SkTypeface::makeClone.
src/c/sk_structs.cpp Adds static_assert to ensure C/C++ palette override struct sizes match.
include/c/sk_typeface.h Introduces sk_fontarguments_palette_override_t and extends the public C API function signature for cloning with arguments.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread include/c/sk_typeface.h
@mattleibow
mattleibow marked this pull request as ready for review April 26, 2026 16:21
@mattleibow mattleibow changed the title Add variable font and color palette C API Add color font palette support to C API Apr 26, 2026
@mattleibow
mattleibow merged commit b9b89f2 into skiasharp Apr 26, 2026
5 checks passed
@mattleibow
mattleibow deleted the dev/font-enhancements branch April 26, 2026 16:31
mattleibow added a commit to mono/SkiaSharp that referenced this pull request Apr 26, 2026
…3742)

Add color font palette support and improve variable font robustness (#3742)

Requires: mono/skia#197

Extends the variable font support merged in #3703 with color font
palette APIs, Span method robustness fixes, and a pre-existing bug fix.

~~ Color font palette support ~~

SkiaSharp:
  * SKTypeface.Clone(int paletteIndex) — clone with a built-in palette
  * SKTypeface.Clone(SKFontArguments) — clone with palette index,
    per-color overrides, variation position, and collection index
  * SKFontArguments ref struct gains PaletteIndex and PaletteOverrides
  * SKFontPaletteOverride struct for individual color entry overrides

HarfBuzzSharp:
  * Face.HasPalettes, PaletteCount — query color font support
  * Face.GetPaletteColors (array + Span) — retrieve palette entries
  * Face.GetPaletteFlags, GetPaletteNameId, GetPaletteColorNameId
  * Face.HasColorLayers, HasColorPng, HasColorSvg

C API (mono/skia#197):
  * sk_fontarguments_palette_override_t struct
  * sk_typeface_clone_with_arguments extended with palette parameters
  * DEF_MAP + static_assert for Palette::Override

~~ Span method robustness ~~

Skia's getVariationDesignParameters/Position use all-or-nothing
semantics: if the buffer is undersized, they return the total count
but write nothing. The C# Span methods now detect this and retry with
a pooled buffer (ArrayPool), copying what fits. Empty spans return 0
immediately without native calls or allocations.

Font.GetVariationCoordsNormalized(Span) fixed to return the written
count instead of the total length when the buffer is undersized.

~~ Bug fix ~~

SKTypeface.ContainsGlyphs(ReadOnlySpan<byte>, SKTextEncoding) had a
pre-existing infinite recursion (called itself instead of
GetFont().ContainsGlyphs) causing StackOverflowException.

~~ Test coverage ~~

Every Span API tested across empty, undersized, exact, and oversized
buffers with exact assertions. Palette APIs tested for colors, flags,
name IDs, different palettes, and negative index validation. Added
InterVariable.ttf (multi-axis) and test_glyphs-COLRv1.ttf (3 palettes)
as test fonts. Gallery sample demonstrates Nabla (COLRv1, 7 palettes,
variable axes) with palette picker and weight/optical size sliders.

Co-authored-by: Ramez Gerges <ramezragaa@proton.me>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants