Skip to content

Commit

Permalink
Add tests for font weight + fix Google Font loading
Browse files Browse the repository at this point in the history
  • Loading branch information
davepagurek committed Dec 15, 2024
1 parent 6517307 commit 7fb18e8
Show file tree
Hide file tree
Showing 21 changed files with 143 additions and 6 deletions.
56 changes: 54 additions & 2 deletions src/type/p5.Font.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* API:
* loadFont("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],200..800&display=swap")
* loadFont("{ font-family: "Bricolage Grotesque", serif; font-optical-sizing: auto; font-weight: <weight> font-style: normal; font-variation-settings: "wdth" 100; });
* loadFont("@font-face { font-family: "Bricolage Grotesque", serif; font-optical-sizing: auto; font-weight: <weight> font-style: normal; font-variation-settings: "wdth" 100; });
* loadFont({
* fontFamily: '"Bricolage Grotesque", serif';
* fontOpticalSizing: 'auto';
Expand Down Expand Up @@ -31,6 +31,14 @@
*/
import Typr from './lib/Typr.js';

function unquote(name) {
// Unquote name from CSS
if ((name.startsWith('"') || name.startsWith("'")) && name.at(0) === name.at(-1)) {
return name.slice(1, -1).replace(/\/(['"])/g, '$1');
}
return name;
}

function font(p5, fn) {

const pathArgCounts = { M: 2, L: 2, C: 6, Q: 4 };
Expand Down Expand Up @@ -455,6 +463,43 @@ function font(p5, fn) {

let { path, name, success, error, descriptors } = parseCreateArgs(...args);

let isCSS = path.includes('@font-face');

if (!isCSS) {
const info = await fetch(path, { method: 'HEAD' });
const isCSSFile = info.headers.get('content-type')?.startsWith('text/css');
if (isCSSFile) {
isCSS = true;
path = await fetch(path).then((res) => res.text());
}
}

if (isCSS) {
const stylesheet = new CSSStyleSheet();
await stylesheet.replace(path);
const fontPromises = [];
for (const rule of stylesheet.cssRules) {
if (rule instanceof CSSFontFaceRule) {
const style = rule.style;
let name = unquote(style.getPropertyValue('font-family'));
const src = style.getPropertyValue('src');
const fontDescriptors = { ...(descriptors || {}) };
for (const key of style) {
if (key === 'font-family' || key === 'src') continue;
const camelCaseKey = key
.replace(/^font-/, '')
.split('-')
.map((v, i) => i === 0 ? v : `${v[0].toUpperCase()}${v.slice(1)}`)
.join('');
fontDescriptors[camelCaseKey] = style.getPropertyValue(key);
}
fontPromises.push(create(this, name, src, fontDescriptors));
}
}
const fonts = await Promise.all(fontPromises);
return fonts[0]; // TODO: handle multiple faces?
}

let pfont;
try {
// load the raw font bytes
Expand All @@ -465,13 +510,20 @@ function font(p5, fn) {

// parse the font data
let fonts = Typr.parse(result);
console.log(fonts[0])
// TODO: generate descriptors from font in the future

if (fonts.length !== 1 || fonts[0].cmap === undefined) {
throw Error(23);
}

// make sure we have a valid name
name = name || extractFontName(fonts[0], path);
if (!name) {
name = extractFontName(fonts[0], path);
if (name.includes(' ')) {
name = name.replace(/ /g, '_');
}
}

// create a FontFace object and pass it to the p5.Font constructor
pfont = await create(this, name, path, descriptors, fonts[0]);
Expand Down
15 changes: 11 additions & 4 deletions src/type/text2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ function text2d(p5, fn) {
};
};

Renderer.prototype._currentTextFont = function() {
return this.states.textFont.font || this.states.textFont.family;
}

/**
* Set the font and [size] and [options] for rendering text
* @param {p5.Font | string} font - the font to use for rendering text
Expand All @@ -269,7 +273,7 @@ function text2d(p5, fn) {
Renderer.prototype.textFont = function (font, size, options) {

if (arguments.length === 0) {
return this.states.textFont;
return this._currentTextFont();
}

let family = font;
Expand All @@ -296,7 +300,7 @@ function text2d(p5, fn) {
}

// check for font-string with size in first arg
if (typeof size === 'undefined' && /[.0-9]+(%|em|p[xt])/.test(family)) {
if (typeof size === 'undefined' && /^[.0-9]+(%|em|p[xt])/.test(family)) {
({ family, size } = this._directSetFontString(family));
}

Expand Down Expand Up @@ -351,7 +355,9 @@ function text2d(p5, fn) {
// the setter
if (typeof weight === 'number') {
this.states.fontWeight = weight;
return this._applyTextProperties();
this._applyTextProperties();
this._setCanvasStyleProperty('font-variation-settings', `"wght" ${weight}`);
return;
}
// the getter
return this.states.fontWeight;
Expand Down Expand Up @@ -410,6 +416,7 @@ function text2d(p5, fn) {
Renderer.prototype.textProperty = function (prop, value, opts) {

let modified = false, debug = opts?.debug || false;
console.log({ prop, value })

// getter: return option from this.states or this.textDrawingContext()
if (typeof value === 'undefined') {
Expand Down Expand Up @@ -605,7 +612,7 @@ function text2d(p5, fn) {
case 'wght':
if (debug) console.log('setting font-weight=' + val);
// manually set the font-weight via the font string
this.textWeight(val);
if (this.states.fontWeight !== val) this.textWeight(val);
return val;
case 'wdth':
if (0) { // attempt to map font-stretch to allowed keywords
Expand Down
Binary file added test/unit/assets/BricolageGrotesque-Variable.ttf
Binary file not shown.
66 changes: 66 additions & 0 deletions test/unit/visual/cases/typography.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,72 @@ visualSuite("Typography", function () {
p5.text("test", 0, 0);
screenshot();
});

visualTest('with a Google Font URL', async function(p5, screenshot) {
p5.createCanvas(100, 100);
const font = await p5.loadFont(
'https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],200..800&display=swap'
);
p5.textFont(font);
p5.textAlign(p5.LEFT, p5.TOP);
p5.textSize(35);
p5.text('p5*js', 0, 10, p5.width);
screenshot();
});
});

visualSuite('textWeight', function() {
visualTest('can control non-variable fonts', async function (p5, screenshot) {
p5.createCanvas(100, 100);
const font = await p5.loadFont(
'https://fonts.googleapis.com/css2?family=Sniglet:wght@400;800&display=swap'
);

for (const weight of [400, 800]) {
p5.background(255);
p5.textFont(font);
p5.textAlign(p5.LEFT, p5.TOP);
p5.textSize(35);
p5.textWeight(weight);
p5.text('p5*js', 0, 10, p5.width);
screenshot();
}
});

visualTest('can control variable fonts', async function (p5, screenshot) {
p5.createCanvas(100, 100);
const font = await p5.loadFont(
'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'
);

for (let weight = 400; weight <= 800; weight += 100) {
p5.background(255);
p5.textFont(font);
p5.textAlign(p5.LEFT, p5.TOP);
p5.textSize(35);
p5.textWeight(weight);
p5.text('p5*js', 0, 10, p5.width);
screenshot();
}
});

visualTest('can control variable fonts from files', async function (p5, screenshot) {
p5.createCanvas(100, 100);
const font = await p5.loadFont(
'/unit/assets/BricolageGrotesque-Variable.ttf',
{ weight: '200 800' }
);

for (let weight = 400; weight <= 800; weight += 100) {
p5.background(255);
p5.textFont(font);
p5.textAlign(p5.LEFT, p5.TOP);
p5.textSize(35);
p5.textWeight(weight);
p5.text('p5*js', 0, 10, p5.width);
screenshot();
}
});
});

visualSuite("textAlign", function () { // TEMPORARY SKIP
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 1
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 2
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 5
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 5
}

0 comments on commit 7fb18e8

Please sign in to comment.