Colorful, graphical fonts in OpenType

Cameron McCormack · @heycam

Colorful, graphical
fonts in OpenType

What is OpenType?

  • Binary font file format (1996)
  • Table-based
    • head – metadata, font style, …
    • hmtx – horizontal metrics
    • cmap – mapping of “character codes” to glyph index values
  • Two classes of glyph format
    • EBDT – embedded bitmap data table
    • glyf & CFF  – outline fonts

Why support coloured glyphs?

  • Text as text, not images
    • Searchable
    • Selectable
    • Editable
    • Accessible
    • Reusable

Current techniques: Layered fonts

+ + =
Forecast Font by Ali Sisk
<span id="cloud"></span><span id="rain"></span><span id="sun"></span>
<style>
  #cloud::before, #rain::before, #sun::before { position: absolute; }
  #cloud::before { content: "\f105"; color: rgb(204, 204, 204); }
  #rain::before  { content: "\f104"; color: rgb(130, 178, 228); }
  #sun::before   { content: "\f101"; color: rgb(255, 165, 0); }
</style>

Current techniques: SVG text

Filled & stroked
<pattern id="polkadot" x="0" y="0" width="20" height="20"
         patternUnits="userSpaceOnUse">
  <rect width="20" height="20" fill="white"/>
  <circle cx="10" cy="10" r="5" fill="crimson"/>
  <circle cx="0"  cy="0"  r="5" fill="crimson"/>
  <circle cx="0"  cy="20" r="5" fill="crimson"/>
  ...
</pattern>
<text fill="url(#polkadot)" stroke="url(#greygradient)">stroked</text>

Prior work – Type 3 Fonts (1984)

  • Arbitrary PostScript programs defining glyphs
  • Shapes filled with patterns, shades, colours
  • Not supported natively in desktop operating systems
  • Not supported by browsers

Prior work – SVG Fonts (2001)

  • SVG document with a font element
  • Two variants:
    • Tiny fonts – plain outline
    • Full fonts – arbitrary SVG content

Prior work – SVG Fonts (2001)

<svg xmlns="http://www.w3.org/2000/svg">
  <font>
    <font-face font-family="MyFontName"
               units-per-em="1000" ascent="800" descent="200"/>
    <glyph unicode="A" horiz-adv-x="700">
      <circle cx="350" cy="400" r="400" fill="red"/>
    </glyph>
  </font>
  <text x="100" y="100" font-family="MyFontName">A</text>
</svg>

Prior work – SVG Fonts (2001)

Pros:
  • Graphically expressive
  • Easily written by hand, modifiable by script
  • Scalable (of course)
  • Animatable!
Cons:
  • Limited font features
  • Does not support non-Latin languages well

Prior work – Apple sbix table (2009?)

  • Initially supported in iPhone OS 3 in Private Use Area
  • Unicode 5 added official code points for emoji
  • Now almost 1000 in Unicode 7
  • iOS 5 and Mac OS X Lion supports the Unicode code points
  • Proprietary, undocumented format
  • Colour bitmaps (PNGs) at multiple sizes

New OpenType table proposals

  • ISO/IEC JTC 1/SC 29/WG 11 working on 3rd edition of Open Font Format (standardised version of OpenType)
  • Submissions were invited for colour glyph proposals

New OpenType table proposal #1

  • CBDT – Google’s color bitmap data table
  • Like Apple’s sbix, allows glyphs defined using embedded PNGs
  • Also allows uncompressed 8 bpp sRGB data
  • Render arbitrary graphics, but won’t scale well
  • No colour parameterisation

New OpenType table proposal #2

  • COLR & CPAL – Microsoft’s coloured glyph layers
  • Font defines one or more palettes
  • Palette entries are RGBA values
  • Coloured glyphs defined as a list of (plain glyph, palette entry) pairs
  • Good fallback
  • Scalable
  • Only flat colours, no gradients or patterns

New OpenType table proposal #2

#RGBA
0204204204255
1130178228255
22551650255
CPAL
#Outline
10       
11       
12       
13       
CFF
#GlyphColor
10110
121
132
COLR
  • Special palette entry 0xFFFF means “foreground color”

New OpenType table proposal #3

  • SVG  – Mozilla and Adobe’s SVG glyphs
  • SVG documents embedded in the font
  • Each document defines one or more glyphs
  • Elements with id="glyph123" define a glyph
  • Full SVG graphics allowed
  • Fallback to plain outline glyphs

New OpenType table proposal #3

<svg xmlns="http://www.w3.org/2000/svg">
  <linearGradient id="bluegrad" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0" stop-color="rgb(130, 178, 228)"/>
    <stop offset="1" stop-color="black"/>
  </linearGradient>
  <g id="glyph61701" transform="scale(1,-1)">
    <path fill="rgb(204, 204, 204)" d="M430 131q0 -26 -18 -44t-43 -18h-4h-23h-0.5h-1.5v0q-9 2 -9 10q0 5 3 8t7 3h1h24h3q16 0 28 12t12 29q0 14 -9 25.5t-24 14.5l-9 1l1 10q1 5 1 10q0 42 -30 72t-73 30q-34 0 -61.5 -20.5t-36.5 -53.5l-2 -7l-7 -1q-24 -2 -40 -19.5t-16 -41.5q0 -20 12 -36.5t31 -22.5 q9 -1 9 -10q0 -4 -3 -7t-8 -3q-2 0 -4 1q-25 7 -41.5 29t-16.5 49q0 32 22 56q19 20 46 25q13 37 45 60t71 23q51 0 87 -36t36 -87v-3q18 -7 29.5 -23t11.5 -35z"/>
    <path fill="url(#bluegrad)" d="M185.5 42q-9.5 6 -12.5 17t3 21q8 13 28.5 29.5t29.5 11.5q7 -9 2 -33t-12 -37q-6 -10 -17.5 -12.5t-21 3.5zM310 140q8 -9 3 -33t-13 -37q-6 -10 -17 -12.5t-21 3.5t-12.5 17t3.5 21q8 13 28 29.5t29 11.5zM262 50q8 -9 3 -33t-13 -37q-6 -10 -17 -13t-21 3t-13 17.5 t3 21.5q8 12 28.5 29t29.5 12z">
      <animateTransform attributeName="transform" type="translate" values="0,0; -100,-120; -100,-120" dur="1s" repeatDur="indefinite"/>
    </path>
    <path fill="rgb(255, 165, 0)" d="M371 360v24q0 8 8 8t8 -8v-24q0 -8 -8 -8t-8 8zM499 275q8 0 8 -8t-8 -8h-25q-8 0 -8 8t8 8h25zM452 330q-6 -6 -11.5 0t-0.5 12l17 17q6 6 12 0t0 -12zM452 204l17 -17q6 -6 0 -11.5t-12 0.5l-17 17q-5 5 0.5 11t11.5 0zM297 359l17 -17q6 -6 0.5 -12t-11.5 0l-17 17 q-6 6 -0.5 12t11.5 0zM374 338q31 1 53.5 -19t24.5 -51q1 -34 -24 -58q-2 -3 -7 -3q-8 -1 -9 8q0 5 4 8q20 18 18 44q-1 24 -18.5 39.5t-40.5 13.5q-15 0 -27 -8q-2 -3 -6 -3q-9 -1 -9 8q-1 5 4 8v0q17 12 37 13z"/>
  </g>
</svg>
A

Context values

  • New SVG property values: context-fill, context-stroke, context-fill-opacity, context-stroke-opacity, context-value
  • <svg xmlns="http://www.w3.org/2000/svg">
      <g id="glyph85"> <!-- for "o" -->
        <circle cx="230" cy="-230" r="200"/>
        <circle cx="230" cy="-230" r="100"
                fill="context-stroke" stroke="none"/>
      </g>
    </svg>
aoz

Palette values

  • Microsoft CPAL table values can be used in SVG glyphs
  • CSS Variables automatically defined for each palette entry
<svg xmlns="http://www.w3.org/2000/svg">
  <g id="glyph61701" transform="scale(1,-1)">
    <path fill="var(--color0)" d="M430 131q0 -26 -18 -44t-43 -18h-4h-23h-0.5h-1.5v0q-9 2 -9 10q0 5 3 8t7 3h1h24h3q16 0 28 12t12 29q0 14 -9 25.5t-24 14.5l-9 1l1 10q1 5 1 10q0 42 -30 72t-73 30q-34 0 -61.5 -20.5t-36.5 -53.5l-2 -7l-7 -1q-24 -2 -40 -19.5t-16 -41.5q0 -20 12 -36.5t31 -22.5 q9 -1 9 -10q0 -4 -3 -7t-8 -3q-2 0 -4 1q-25 7 -41.5 29t-16.5 49q0 32 22 56q19 20 46 25q13 37 45 60t71 23q51 0 87 -36t36 -87v-3q18 -7 29.5 -23t11.5 -35z"/>
    <path fill="var(--color1)" d="M185.5 42q-9.5 6 -12.5 17t3 21q8 13 28.5 29.5t29.5 11.5q7 -9 2 -33t-12 -37q-6 -10 -17.5 -12.5t-21 3.5zM310 140q8 -9 3 -33t-13 -37q-6 -10 -17 -12.5t-21 3.5t-12.5 17t3.5 21q8 13 28 29.5t29 11.5zM262 50q8 -9 3 -33t-13 -37q-6 -10 -17 -13t-21 3t-13 17.5 t3 21.5q8 12 28.5 29t29.5 12z"/>
    <path fill="var(--color2)" d="M371 360v24q0 8 8 8t8 -8v-24q0 -8 -8 -8t-8 8zM499 275q8 0 8 -8t-8 -8h-25q-8 0 -8 8t8 8h25zM452 330q-6 -6 -11.5 0t-0.5 12l17 17q6 6 12 0t0 -12zM452 204l17 -17q6 -6 0 -11.5t-12 0.5l-17 17q-5 5 0.5 11t11.5 0zM297 359l17 -17q6 -6 0.5 -12t-11.5 0l-17 17 q-6 6 -0.5 12t11.5 0zM374 338q31 1 53.5 -19t24.5 -51q1 -34 -24 -58q-2 -3 -7 -3q-8 -1 -9 8q0 5 4 8q20 18 18 44q-1 24 -18.5 39.5t-40.5 13.5q-15 0 -27 -8q-2 -3 -6 -3q-9 -1 -9 8q-1 5 4 8v0q17 12 37 13z"/>
  </g>
</svg>

Compared to SVG Fonts

  • No metrics in the SVG document
  • Coordinate space is y-down rather than y-up
  • Better mapping of fill & stroke to parts of the glyph
  • Use OpenType features for
    • combining mark positioning
    • language-based glyph substitution
    • defining small-caps, lining numerals, swashes (font-variant)

Which proposal was accepted?

  • All three of them!
  • Different use cases, pros/cons for each
  • Draft International Standard just published

Shaded shadows

A B C

Future work needed

  • A way to select a palette from the font?
    @font-face {
      font-family: MyColourfulFont;
      src: url(...);
    }
    
    h1 { font: 64px MyColourfulFont; font-palette: 2; }
  • A way to specify custom palette values?
    h1 { font-palette-values: blue, orange; }

Where is this supported?

  • In browsers, when referenced with @font-face:
    • CBDT – none
    • COLR – Firefox, Internet Explorer
    • SVG  – Firefox
  • In font editors:
    • CBDT – TransType
    • COLR – TransType, FontCreator, glyphs.app
    • SVG  – TransType, SVG-OT Workshop

Thank You

Cameron McCormack · Mozilla · @heycam

Shower, by Vadim Makeev, Opera Software
Mozilla styling, by Chris Heilmann, Mozilla
Fonts: Fascinate, by Astigmatic; Passion One, by Fontstage; Forecast Font by Ali Sisk

Acknowledgements