Skip to content

Commit 4e0f57a

Browse files
authored
Merge pull request #7440 from dhowe/dev-2.0
Type: implement #7147 and minor refactors
2 parents 83c6db9 + 7235640 commit 4e0f57a

File tree

3 files changed

+140
-62
lines changed

3 files changed

+140
-62
lines changed

src/type/p5.Font.js

+58-54
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,6 @@
3232
import Typr from './lib/Typr.js';
3333
import { createFromCommands } from '@davepagurek/bezier-path';
3434

35-
function unquote(name) {
36-
// Unquote name from CSS
37-
if ((name.startsWith('"') || name.startsWith("'")) && name.at(0) === name.at(-1)) {
38-
return name.slice(1, -1).replace(/\/(['"])/g, '$1');
39-
}
40-
return name;
41-
}
42-
4335
function font(p5, fn) {
4436

4537
const pathArgCounts = { M: 2, L: 2, C: 6, Q: 4 };
@@ -62,53 +54,18 @@ function font(p5, fn) {
6254
this.face = fontFace;
6355
}
6456

65-
verticalAlign(size) {
66-
const { sCapHeight } = this.data?.['OS/2'] || {};
67-
const { unitsPerEm = 1000 } = this.data?.head || {};
68-
const { ascender = 0, descender = 0 } = this.data?.hhea || {};
69-
const current = ascender / 2;
70-
const target = (sCapHeight || (ascender + descender)) / 2;
71-
const offset = target - current;
72-
return offset * size / unitsPerEm;
73-
}
74-
75-
variations() {
76-
let vars = {};
77-
if (this.data) {
78-
let axes = this.face?.axes;
79-
if (axes) {
80-
axes.forEach(ax => {
81-
vars[ax.tag] = ax.value;
82-
});
83-
}
84-
}
85-
fontFaceVariations.forEach(v => {
86-
let val = this.face[v];
87-
if (val !== 'normal') {
88-
vars[v] = vars[v] || val;
89-
}
90-
});
91-
return vars;
92-
}
93-
94-
metadata() {
95-
let meta = this.data?.name || {};
96-
for (let p in this.face) {
97-
if (!/^load/.test(p)) {
98-
meta[p] = meta[p] || this.face[p];
99-
}
100-
}
101-
return meta;
102-
}
103-
104-
fontBounds(...args) { // alias for p5.fontBounds
105-
if (!this._pInst) throw Error('p5 required for fontBounds()');
106-
return this._pInst.fontBounds(...args);
57+
fontBounds(str, x, y, width, height, options) {
58+
({ width, height, options } = this._parseArgs(width, height, options));
59+
let renderer = options?.graphics?._renderer || this._pInst._renderer;
60+
if (!renderer) throw Error('p5 or graphics required for fontBounds()');
61+
return renderer.fontBounds(str, x, y, width, height);
10762
}
10863

109-
textBounds(...args) { // alias for p5.textBounds
110-
if (!this._pInst) throw Error('p5 required for textBounds()'); // TODO:
111-
return this._pInst.textBounds(...args);
64+
textBounds(str, x, y, width, height, options) {
65+
({ width, height, options } = this._parseArgs(width, height, options));
66+
let renderer = options?.graphics?._renderer || this._pInst._renderer;
67+
if (!renderer) throw Error('p5 or graphics required for fontBounds()');
68+
return renderer.textBounds(str, x, y, width, height);
11269
}
11370

11471
textToPaths(str, x, y, width, height, options) {
@@ -208,6 +165,35 @@ function font(p5, fn) {
208165
return geom;
209166
}
210167

168+
variations() {
169+
let vars = {};
170+
if (this.data) {
171+
let axes = this.face?.axes;
172+
if (axes) {
173+
axes.forEach(ax => {
174+
vars[ax.tag] = ax.value;
175+
});
176+
}
177+
}
178+
fontFaceVariations.forEach(v => {
179+
let val = this.face[v];
180+
if (val !== 'normal') {
181+
vars[v] = vars[v] || val;
182+
}
183+
});
184+
return vars;
185+
}
186+
187+
metadata() {
188+
let meta = this.data?.name || {};
189+
for (let p in this.face) {
190+
if (!/^load/.test(p)) {
191+
meta[p] = meta[p] || this.face[p];
192+
}
193+
}
194+
return meta;
195+
}
196+
211197
static async list(log = false) { // tmp
212198
if (log) {
213199
console.log('There are', document.fonts.size, 'font-faces\n');
@@ -228,6 +214,16 @@ function font(p5, fn) {
228214
}
229215

230216
/////////////////////////////// HELPERS ////////////////////////////////
217+
218+
_verticalAlign(size) {
219+
const { sCapHeight } = this.data?.['OS/2'] || {};
220+
const { unitsPerEm = 1000 } = this.data?.head || {};
221+
const { ascender = 0, descender = 0 } = this.data?.hhea || {};
222+
const current = ascender / 2;
223+
const target = (sCapHeight || (ascender + descender)) / 2;
224+
const offset = target - current;
225+
return offset * size / unitsPerEm;
226+
}
231227

232228
/*
233229
Returns an array of line objects, each containing { text, x, y, glyphs: [ {g, path} ] }
@@ -579,7 +575,7 @@ function font(p5, fn) {
579575

580576
// parse the font data
581577
let fonts = Typr.parse(result);
582-
console.log(fonts[0])
578+
583579
// TODO: generate descriptors from font in the future
584580

585581
if (fonts.length !== 1 || fonts[0].cmap === undefined) {
@@ -635,6 +631,14 @@ function font(p5, fn) {
635631
return new p5.Font(pInst, face, name, path, rawFont);
636632
}
637633

634+
function unquote(name) {
635+
// Unquote name from CSS
636+
if ((name.startsWith('"') || name.startsWith("'")) && name.at(0) === name.at(-1)) {
637+
return name.slice(1, -1).replace(/\/(['"])/g, '$1');
638+
}
639+
return name;
640+
}
641+
638642
function createFontFace(name, path, descriptors, rawFont) {
639643
let fontArg = rawFont?._data;
640644
if (!fontArg) {

src/type/text2d.js

+6-8
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ function text2d(p5, fn) {
9494
}
9595
return this._renderer[func](...args);
9696
};
97-
// TODO: is this necessary?
9897
p5.Graphics.prototype[func] = function (...args) {
9998
return this._renderer[func](...args);
10099
};
@@ -160,8 +159,7 @@ function text2d(p5, fn) {
160159
* @returns - a bounding box object for the text block: {x,y,w,h}
161160
*/
162161
Renderer.prototype.textBounds = function (str, x, y, width, height) {
163-
//console.log('TEXT BOUNDS: ', str, x, y, width, height);
164-
// delegate to _textBoundsSingle measure function
162+
// delegate to _textBoundsSingle for measuring
165163
return this._computeBounds(fn._TEXT_BOUNDS, str, x, y, width, height).bounds;
166164
};
167165

@@ -175,7 +173,7 @@ function text2d(p5, fn) {
175173
* @returns - a bounding box object for the text block: {x,y,w,h}
176174
*/
177175
Renderer.prototype.fontBounds = function (str, x, y, width, height) {
178-
// delegate to _fontBoundsSingle measure function
176+
// delegate to _fontBoundsSingle for measuring
179177
return this._computeBounds(fn._FONT_BOUNDS, str, x, y, width, height).bounds;
180178
};
181179

@@ -260,7 +258,7 @@ function text2d(p5, fn) {
260258
};
261259
};
262260

263-
Renderer.prototype._currentTextFont = function() {
261+
Renderer.prototype._currentTextFont = function () {
264262
return this.states.textFont.font || this.states.textFont.family;
265263
}
266264

@@ -1089,7 +1087,7 @@ function text2d(p5, fn) {
10891087
};
10901088

10911089
if (p5.Renderer2D) {
1092-
p5.Renderer2D.prototype.textDrawingContext = function() {
1090+
p5.Renderer2D.prototype.textDrawingContext = function () {
10931091
return this.drawingContext;
10941092
};
10951093
p5.Renderer2D.prototype._renderText = function (text, x, y, maxY, minY) {
@@ -1187,7 +1185,7 @@ function text2d(p5, fn) {
11871185
}
11881186
}
11891187
if (p5.RendererGL) {
1190-
p5.RendererGL.prototype.textDrawingContext = function() {
1188+
p5.RendererGL.prototype.textDrawingContext = function () {
11911189
if (!this._textDrawingContext) {
11921190
this._textCanvas = document.createElement('canvas');
11931191
this._textCanvas.width = 1;
@@ -1252,7 +1250,7 @@ function text2d(p5, fn) {
12521250
console.warn(`${textBaseline} is not supported in WebGL mode.`); // FES?
12531251
break;
12541252
}
1255-
yOff += this.states.textFont.font?.verticalAlign(textSize) || 0;
1253+
yOff += this.states.textFont.font?._verticalAlign(textSize) || 0;
12561254
dataArr.forEach(ele => ele.y += yOff);
12571255
return dataArr;
12581256
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<html>
2+
3+
<!--
4+
CSS-style font properties (preferred, but doesn't support custom axes):
5+
font-weight: 650;
6+
font-style: oblique 80deg; (must add deg)
7+
font-stretch: 75%; (only accepts percentage with %)
8+
font-optical-sizing: auto; (only allows for 'auto' or 'none')
9+
Font-variation style properties:
10+
font-variations-settings: 'wght' 650, 'slnt' 80, 'wdth' 75, 'opsz' 100;
11+
-->
12+
13+
<head>
14+
<meta charset='UTF-8'>
15+
<!-- <script language="javascript" type="text/javascript" src="./lib/Typr.js"></script>
16+
<script language="javascript" type="text/javascript" src="./lib/Typr.U.js"></script> -->
17+
18+
<style>
19+
body {
20+
padding: 0;
21+
margin: 0;
22+
}
23+
24+
canvas {
25+
border: 1px solid #f0f0f0;
26+
display: block;
27+
}
28+
29+
img {
30+
border: 1px solid #fff;
31+
}
32+
33+
div {
34+
margin: 100px 0px;
35+
}
36+
</style>
37+
</head>
38+
39+
40+
41+
<body>
42+
<script type='module'>
43+
import p5 from '../../../src/app.js';
44+
let sketch = async function (p) {
45+
let f, g, pts;
46+
p.setup = async function () {
47+
p.createCanvas(400, 300);
48+
f = await p.loadFont("https://fonts.gstatic.com/s/opensans/v40/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsg-1y4nY1M2xLER.ttf");
49+
g = p.createGraphics(p.width, p.height)
50+
g.background(220);
51+
g.textAlign(p.CENTER, p.CENTER)
52+
g.textFont(f, 50);
53+
54+
g.text('Serendipity', g.width / 2, g.height / 2);
55+
//let bb = g.textBounds('Serendipity', g.width / 2, g.height / 2);
56+
let bb = f.textBounds('Serendipity', g.width / 2, g.height / 2, { graphics: g });
57+
g.noFill();
58+
g.stroke(0);
59+
g.rect(bb.x, bb.y, bb.w, bb.h);
60+
61+
pts = f.textToPoints('Serendipity', g.width / 2, g.height / 2, { graphics: g });
62+
pts.forEach((pt, i) => {
63+
g.fill(0);
64+
g.circle(pt.x, pt.y, 2);
65+
});
66+
p.image(g, 0, 0);
67+
}
68+
}
69+
70+
new p5(sketch);
71+
</script>
72+
73+
</body>
74+
75+
76+
</html>

0 commit comments

Comments
 (0)