Skip to content

[COLR] IR stores resolved colors instead of palette indices, lossy for duplicate CPAL entries #1905

Description

@anthrotype

The IR represents color layer fills as resolved Color values (PaintSolid { color: Option<Color> }), not palette indices. Both frontends (glyphs2fontir and soon ufo2fontir via #1904) resolve palette indices to colors by looking up the first palette 0, and the backend reconstructs indices via ColorPalettes::index_of() which similarly searches palette 0 for a matching color.

This round-trip is lossy if palette 0 contains duplicate color values at different indices. The CPAL spec does not require entries to be unique. A font may intentionally use the same color at two indices in palette 0 if they diverge in alternate palettes (e.g., a "monochrome" palette where distinct colors collapse).

In that case, index_of returns the first match, silently remapping the original index.

I propose we fix this by storing palette indices in the IR instead of resolved colors. PaintSolid would hold an Option<u16> (palette index, None for 0xFFFF foreground) instead of Option<Color>. Similarly for gradient ColorStop.

This would move palette construction entirely into the frontends:

  • UFO: already has indices in the source, pass through directly
  • Glyphs with explicit (COLRv0) colorPalette layer attribute: already has indices, pass through
  • Glyphs (COLRv1) with inline colors: frontend builds the palette from unique colors, then maps each color -> index. Unambiguous since the palette itself is derived from those exact colors.

The backend would consume indices directly, eliminating the lossy index_of color matching.

A trade off is the Glyphs ColorGlyphsWork which currently has no dependency on ColorPaletteWork would need to read the palette from context to resolve inline colors -> indices, adding a work graph dependency. Negligible perf impact since palette construction is fast.

Alternatives are validating that palette 0 has no duplicate colors and error early (rejects spec-valid fonts) or accept the limitation and document it (pragmatic given real-world fonts with duplicate palette 0 entries are rare).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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