Automattic / Automattic/node-canvas

Canvas doesn't use loaded fonts as fallback font

Open
#1,997 6 comments 0 reactions 0 assignees View on GitHub
Text & Fonts
Dominant language
JavaScript
Stars
10.7k
Forks
1.2k
Avg merge
4d 8h
Merged PRs (30d)
1

Description

## Issue or Feature
Node Canvas doesn't fall back to loaded fonts if it encounters an unknown character

When loading fonts with `canvas.registerFont()`, the loaded fonts aren't used if they support a character the mainly used font does not, if fonts are installed on the system, too.
That means, if I run this on a VPS without any installed fonts, it works as expected, falling back to whatever font supports a character if it encounters one the main font doesn't support.
But if I run it on my local machine, this doesn't happen.

I'm faily sure this issue lies with installed system fonts, because a variation of this also occurs when trying to use a font file with the same font family as a system font (see below for more details)

## Steps to Reproduce
```javascript
//load a fallback font that DEFINITELY supports the character (code2000)
canvas.registerFont('./Assets/Fonts/code2000.ttf', {family: 'Code2000'})

//load the Uni Sans Heavy custom font
canvas.registerFont('./Assets/Fonts/Uni_Sans_Heavy.ttf', {family: 'Uni Sans'})

let cnvs = canvas.createCanvas(740, 260)
let ctx = cnvs.getContext('2d')
ctx.fillStyle = "#fff"
ctx.font = '50px Uni Sans'
ctx.fillText(`HELLO WORLD, I'M ᗩcł!`, 50, 100);

//result doesn't display the "ᗩ" character correctly on my local machine, but everything works fine on a VPS
```

Result on local machine: https://i.stack.imgur.com/yR2ue.png

## Using a font file with the same font family as a system font
Like mentioned above, something similar occurs when trying to use a font file, but having a font with the same name installed on the system
```javascript
canvas.registerFont('/Assets/Fonts/uni_sans_heavy.ttf', {family: 'Uni Sans'})

let cnvs = canvas.createCanvas(500, 150)
let ctx = cnvs.getContext('2d')

ctx.font = 'bold 50px Uni Sans'

ctx.fillText(`This is a test!`, 25, 50)
```
The above code DOESN'T use the Uni_Sans_Heavy.ttf file I register, nor does it use the system font, instead it uses another (to me unknown) font, when run on my local machine.
However, before I installed the UniSans font to my system, everything worked fine. Running the code on my VPS, which doesn't have any installed fonts either also produces no issues.

**tl;dr: Node Canvas fonts behave strangely with system fonts and font files clashing in certain instances. Is there a way to force it to use a font file instead? Is there a way to force it to use certain fonts as fallback fonts?**

## Your Environment
* Version of node-canvas (output of `npm list canvas` or `yarn list canvas`): 2.9.0
* Environment (e.g. node 4.2.0 on Mac OS X 10.8): Node v16.14.0 on Windows 11

Contributor guide

No contributing guide indexed for this repository

Research direction

Reproduce the behavior with canvas.registerFont(), createCanvas(), getContext(), and fillText() using the supplied fonts and environments. Then trace font selection and fallback for registered versus system fonts; done means registered fallback characters render consistently and a registered font wins over a same-family system font.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.