Skip to content

Commit 16f87eb

Browse files
authored
Merge pull request #1970 from processing/dhowe-fix-to-bounds-detection
Fixes bug in bounds detection
2 parents 9ac17cf + d10bf4f commit 16f87eb

File tree

4 files changed

+154
-69
lines changed

4 files changed

+154
-69
lines changed

src/typography/p5.Font.js

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,8 @@ var constants = require('../core/constants');
1414

1515
/*
1616
* TODO:
17-
*
18-
* API:
19-
* -- textBounds()
20-
* -- getPath()
21-
* -- getPoints()
22-
*
23-
* ===========================================
24-
* -- PFont functions:
25-
* PFont.list()
26-
*
2717
* -- kerning
2818
* -- alignment: justified?
29-
* -- integrate p5.dom? (later)
3019
*/
3120

3221
/**
@@ -106,44 +95,27 @@ p5.Font.prototype.textBounds = function(str, x, y, fontSize, options) {
10695
// settings. Default alignment should match opentype's origin: left-aligned &
10796
// alphabetic baseline.
10897
var p = (options && options.renderer && options.renderer._pInst) ||
109-
this.parent,
110-
ctx = p._renderer.drawingContext,
98+
this.parent, ctx = p._renderer.drawingContext,
11199
alignment = ctx.textAlign || constants.LEFT,
112-
baseline = ctx.textBaseline || constants.BASELINE;
113-
var result = this.cache[cacheKey('textBounds', str, x, y, fontSize, alignment,
114-
baseline)];
100+
baseline = ctx.textBaseline || constants.BASELINE,
101+
key = cacheKey('textBounds', str, x, y, fontSize, alignment, baseline),
102+
result = this.cache[key];
115103

116104
if (!result) {
117105

118-
var xCoords = [], yCoords = [], self = this,
119-
scale = this._scale(fontSize), minX, minY, maxX, maxY;
106+
var minX, minY, maxX, maxY, pos, xCoords = [], yCoords = [],
107+
scale = this._scale(fontSize);
120108

121109
this.font.forEachGlyph(str, x, y, fontSize, options,
122110
function(glyph, gX, gY, gFontSize) {
123111

124-
xCoords.push(gX);
125-
yCoords.push(gY);
126-
127112
var gm = glyph.getMetrics();
128-
129-
if (glyph.name !== 'space' && glyph.unicode !== 32) {
130-
131-
xCoords.push(gX + (gm.xMax * scale));
132-
yCoords.push(gY + (-gm.yMin * scale));
133-
yCoords.push(gY + (-gm.yMax * scale));
134-
135-
} else { // NOTE: deals with broken metrics for spaces in opentype.js
136-
137-
xCoords.push(gX + self.font.charToGlyph(' ').advanceWidth *
138-
self._scale(fontSize));
139-
}
113+
xCoords.push(gX + (gm.xMin * scale));
114+
xCoords.push(gX + (gm.xMax * scale));
115+
yCoords.push(gY + (-gm.yMin * scale));
116+
yCoords.push(gY + (-gm.yMax * scale));
140117
});
141118

142-
// fix to #1409 (not sure why these max() functions were here)
143-
/*minX = Math.max(0, Math.min.apply(null, xCoords));
144-
minY = Math.max(0, Math.min.apply(null, yCoords));
145-
maxX = Math.max(0, Math.max.apply(null, xCoords));
146-
maxY = Math.max(0, Math.max.apply(null, yCoords));*/
147119
minX = Math.min.apply(null, xCoords);
148120
minY = Math.min.apply(null, yCoords);
149121
maxX = Math.max.apply(null, xCoords);
@@ -158,15 +130,15 @@ p5.Font.prototype.textBounds = function(str, x, y, fontSize, options) {
158130
};
159131

160132
// Bounds are now calculated, so shift the x & y to match alignment settings
161-
var textWidth = result.w + result.advance;
162-
var pos = this._handleAlignment(p, ctx, str, result.x, result.y, textWidth);
133+
pos = this._handleAlignment(p, ctx, str, result.x, result.y,
134+
result.w + result.advance);
135+
163136
result.x = pos.x;
164137
result.y = pos.y;
165138

166139
this.cache[cacheKey('textBounds', str, x, y, fontSize, alignment,
167140
baseline)] = result;
168141
}
169-
//else console.log('cache-hit');
170142

171143
return result;
172144
};
@@ -409,11 +381,6 @@ p5.Font.prototype._renderPath = function(line, x, y, options) {
409381

410382
p5.Font.prototype._textWidth = function(str, fontSize) {
411383

412-
if (str === ' ') { // special case for now
413-
414-
return this.font.charToGlyph(' ').advanceWidth * this._scale(fontSize);
415-
}
416-
417384
var bounds = this.textBounds(str, 0, 0, fontSize);
418385
return bounds.w + bounds.advance;
419386
};
107 KB
Binary file not shown.

test/manual-test-examples/p5.Font/simple/index.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
<meta charset="UTF-8">
44
<script language="javascript" type="text/javascript" src="../../../../lib/p5.js"></script>
55
<script language="javascript" type="text/javascript" src="sketch.js"></script>
6-
<style> body {padding: 0; margin: 0;} canvas{border: 1px solid #f0f0f0; display: block;} img{ border: 1px solid #f0f;} div{ margin: 10px 0px;}</style>
6+
<style> body {padding: 0; margin: 0; font-size: 10px } canvas{border: 1px solid #f0f0f0; display: block;} img{ border: 1px solid #f0f;} div{ margin: 10px 0px;}</style>
77
</head>
88

99
<body>
1010
<div id='textSketch'></div>
11+
Note: (tight) bounds for a text string <i>may</i> start to the right of the its x-position (blue line)<br />
12+
<div id='textSketchMono'></div><br />&nbsp;<br />
13+
Issue #1958:
14+
<div id='textSketch1958'></div>
15+
<!--div id='textSketch1957'></div-->
1116
</body>
1217
</html>
Lines changed: 135 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,152 @@
1+
var _setup = function(p, font) {
2+
var txt, tb, tw, x = 20, y = 50;
3+
4+
p.createCanvas(240, 160);
5+
p.textFont(font);
6+
p.textSize(20);
7+
8+
p.stroke("blue");
9+
p.line(x, 0, x, p.height);
10+
11+
txt = " leading space";
12+
tb = font.textBounds(txt, x, y);
13+
tw = p.textWidth(txt);
14+
p.stroke("black");
15+
p.rect(tb.x, tb.y, tb.w, tb.h);
16+
p.noStroke();
17+
p.text(txt, x, y);
18+
p.stroke("red");
19+
p.line(x, y + 6, x + tw, y + 6);
20+
21+
y = 80;
22+
txt = "traction waste";
23+
tb = font.textBounds(txt, x, y);
24+
tw = p.textWidth(txt);
25+
p.stroke("black");
26+
p.rect(tb.x, tb.y, tb.w, tb.h);
27+
p.noStroke();
28+
p.text(txt, x, y);
29+
p.stroke("red");
30+
p.line(x, y + 6, x + tw, y + 6);
31+
32+
y = 110;
33+
txt = "trailing space ";
34+
tb = font.textBounds(txt, x, y);
35+
tw = p.textWidth(txt);
36+
p.stroke("black");
37+
p.rect(tb.x, tb.y, tb.w, tb.h);
38+
p.noStroke();
39+
p.text(txt, x, y);
40+
p.stroke("red");
41+
p.line(x, y + 6, x + tw, y + 6);
42+
43+
y = 140;
44+
txt = " ";
45+
tb = font.textBounds(txt, x, y);
46+
tw = p.textWidth(txt);
47+
p.stroke("black");
48+
p.rect(tb.x, tb.y, tb.w, p.max(tb.h, 3));
49+
p.noStroke();
50+
p.text(txt, x, y);
51+
p.stroke("red");
52+
p.line(x, y + 6, x + tw, y + 6);
53+
};
154

255
var textSketch = function(p) {
56+
p.setup = function() {
57+
p.loadFont("../acmesa.ttf", function(f) {
58+
_setup(p, f);
59+
});
60+
};
61+
};
362

4-
var font, txt, tb;
63+
var textSketchMono = function(p) {
64+
p.setup = function() {
65+
p.loadFont("../AndaleMono.ttf", function(f) {
66+
_setup(p, f);
67+
});
68+
};
69+
};
70+
71+
var textSketch1958 = function(p) { // issue #1958
72+
var font, lineW, words = "swimming back to the rock";
573

674
p.preload = function() {
7-
font = p.loadFont("../acmesa.ttf");
75+
font = p.loadFont("../OpenSans-Regular.ttf");
876
};
977

1078
p.setup = function() {
79+
function textAsWords(words, x, y) {
80+
var tw, spaceW = p.textWidth(" ");
81+
console.log(spaceW);
82+
for (var i = 0; i < words.length; i++) {
83+
if (i != 0) {
84+
tw = p.textWidth(words[i - 1]);
85+
x += tw + spaceW;
86+
p.stroke(0);
87+
p.noFill();
88+
p.rect(x - spaceW, y + 5, spaceW, -25);
89+
}
90+
p.fill(0);
91+
p.noStroke();
92+
p.text(words[i], x, y);
93+
}
94+
}
1195

12-
p.createCanvas(240, 160);
13-
p.textFont(font);
14-
p.textSize(20);
96+
p.createCanvas(300, 200);
97+
p.background(255);
1598

16-
txt = ' space first';
17-
var tb = font.textBounds(txt,50,50,20);
18-
p.rect(tb.x,tb.y,tb.w,tb.h);
19-
p.text(txt, 50, 50);
99+
p.textSize(20); // Case 1: Default font
100+
p.noStroke();
101+
p.text(words, 20, 50);
102+
textAsWords(words.split(" "), 20, 80);
20103

21-
txt = 'trailing space?'
22-
tb = font.textBounds(txt,50,80,20);
23-
p.rect(tb.x,tb.y,tb.w,tb.h);
24-
p.text(txt, 50, 80);
104+
p.stroke(255, 0, 0);
105+
p.line(20, 0, 20, p.height);
25106

26-
txt = 'trailing space? '
27-
tb = font.textBounds(txt,50,110,20);
28-
p.rect(tb.x,tb.y,tb.w,tb.h);
29-
p.text(txt, 50, 110);
107+
lineW = p.textWidth(words);
108+
p.line(20 + lineW, 0, 20 + lineW, 90);
30109

31-
var tw = font._textWidth(txt);
32-
tb = font.textBounds(' ',50,140,20);
33-
p.rect(tb.x,tb.y,tb.w,tb.h);
34-
};
110+
p.textFont(font, 20); // Case 2: OpenSans
111+
p.noStroke();
112+
p.text(words, 20, 120);
113+
textAsWords(words.split(" "), 20, 150);
35114

115+
p.stroke(255, 0, 0);
116+
lineW = p.textWidth(words);
117+
p.line(20 + lineW, 100, 20 + lineW, p.height - 20);
118+
119+
p.stroke(0);
120+
p.line(20, 160, 20 + p.textWidth(" "), 160);
121+
};
36122
};
37123

124+
/*var textSketch1957 = function(p) { // issue #1957
125+
var font;
126+
p.preload = function() {
127+
font = p.loadFont("../AndaleMono.ttf");
128+
};
129+
p.setup = function() {
130+
131+
p.createCanvas(300, 400);
132+
p.textFont(font, 80);
133+
134+
p.text("a", 0, 100);
135+
p.text("b", 0, 200);
136+
p.text("c", 0, 300);
137+
138+
p.stroke(255,0,0);
139+
p.line(p.textWidth("a"), 0, p.textWidth("a"), p.height);
140+
p.line(p.textWidth("b"), 0, p.textWidth("b"), p.height);
141+
p.line(p.textWidth("c"), 0, p.textWidth("c"), p.height);
142+
p.noStroke();
143+
p.textSize(10);
144+
p.text("a="+p.textWidth("a")+" b="+p.textWidth("b")+" c="+p.textWidth("c"), 10, 350);
145+
console.log(font);
146+
}
147+
}
148+
new p5(textSketch1957, "textSketch1957");*/
38149

39-
new p5(textSketch, 'textSketch');
150+
new p5(textSketch, "textSketch");
151+
new p5(textSketchMono, "textSketchMono");
152+
new p5(textSketch1958, "textSketch1958");

0 commit comments

Comments
 (0)