Skip to content

Commit

Permalink
Expose "fontAscent" in metrics to support baseline alignment.
Browse files Browse the repository at this point in the history
Return "sdfWidth/sdfHeight" separately in the metrics (don't make caller try to calculate the right size).
Fix backwards compatibility:
- Revert rename of this.size to this.canvasSize
- When metrics aren't enabled, don't use the "don't read pixels in the buffer area" optimization, because many glyphs actually overflow into that area.
  • Loading branch information
ChrisLoer committed Jan 15, 2021
1 parent 26f3bd3 commit 304b377
Showing 1 changed file with 25 additions and 16 deletions.
41 changes: 25 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function TinySDF(fontSize, buffer, radius, cutoff, fontFamily, fontWeight) {

// For backwards compatibility, we honor the implicit contract that the
// size of the returned bitmap will be fontSize + buffer * 2
var size = this.canvasSize = this.fontSize + this.buffer * 2;
var size = this.size = this.fontSize + this.buffer * 2;
// Glyphs may be slightly larger than their fontSize. The canvas already
// has buffer space, but create extra buffer space in the output grid for the
// "halo" to extend into (if metric extraction is enabled)
Expand All @@ -40,14 +40,16 @@ function TinySDF(fontSize, buffer, radius, cutoff, fontFamily, fontWeight) {
this.middle = Math.round((size / 2) * (navigator.userAgent.indexOf('Gecko/') >= 0 ? 1.2 : 1));
}

function prepareGrids(imgData, width, height, glyphWidth, glyphHeight, gridOuter, gridInner, buffer) {
function prepareGrids(imgData, width, height, glyphWidth, glyphHeight, gridOuter, gridInner) {
// Initialize grids outside the glyph range to alpha 0
gridOuter.fill(INF, 0, width * height);
gridInner.fill(0, 0, width * height);

var offset = (width - glyphWidth) / 2; // This is zero if we're not extracting metrics

for (var y = 0; y < glyphHeight; y++) {
for (var x = 0; x < glyphWidth; x++) {
var j = (y + buffer) * width + x + buffer;
var j = (y + offset) * width + x + offset;
var a = imgData.data[4 * (y * glyphWidth + x) + 3] / 255; // alpha value
if (a === 1) {
gridOuter[j] = 0;
Expand Down Expand Up @@ -79,40 +81,44 @@ TinySDF.prototype._draw = function (char, getMetrics) {
var advance = textMetrics.width;

var doubleBuffer = 2 * this.buffer;
var glyphWidth = this.canvasSize - doubleBuffer;
var glyphHeight = this.canvasSize - doubleBuffer;
var top = -this.canvasSize / 3;
var width, glyphWidth, height, glyphHeight, top;

var imgTop = this.buffer;
var imgTop, imgLeft;
// If the browser supports bounding box metrics, we can generate a smaller
// SDF. This is a significant performance win.
if (getMetrics && textMetrics.actualBoundingBoxLeft !== undefined) {
// The integer/pixel part of the top alignment is encoded in metrics.top
// The remainder is implicitly encoded in the rasterization
top = Math.floor(textMetrics.actualBoundingBoxAscent) - this.middle;
imgTop = Math.max(0, this.middle - Math.ceil(textMetrics.actualBoundingBoxAscent));
imgLeft = this.buffer;

// If the glyph overflows the canvas size, it will be clipped at the
// bottom/right
glyphWidth = Math.min(this.canvasSize,
glyphWidth = Math.min(this.size,
Math.ceil(textMetrics.actualBoundingBoxRight - textMetrics.actualBoundingBoxLeft));
glyphHeight = Math.min(this.canvasSize - imgTop,
glyphHeight = Math.min(this.size - imgTop,
Math.ceil(textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent));
}

var width = glyphWidth + doubleBuffer;
var height = glyphHeight + doubleBuffer;
width = glyphWidth + doubleBuffer;
height = glyphHeight + doubleBuffer;
} else {
width = glyphWidth = this.size;
height = glyphHeight = this.size
top = 0;
imgTop = imgLeft = 0;
}

var imgData;
if (glyphWidth && glyphHeight) {
this.ctx.clearRect(this.buffer, imgTop, glyphWidth, glyphHeight);
this.ctx.clearRect(imgLeft, imgTop, glyphWidth, glyphHeight);
this.ctx.fillText(char, this.buffer, this.middle);
imgData = this.ctx.getImageData(this.buffer, imgTop, glyphWidth, glyphHeight);
imgData = this.ctx.getImageData(imgLeft, imgTop, glyphWidth, glyphHeight);
}

var alphaChannel = new Uint8ClampedArray(width * height);

prepareGrids(imgData, width, height, glyphWidth, glyphHeight, this.gridOuter, this.gridInner, this.buffer);
prepareGrids(imgData, width, height, glyphWidth, glyphHeight, this.gridOuter, this.gridInner);

edt(this.gridOuter, width, height, this.f, this.v, this.z);
edt(this.gridInner, width, height, this.f, this.v, this.z);
Expand All @@ -124,9 +130,12 @@ TinySDF.prototype._draw = function (char, getMetrics) {
metrics: {
width: glyphWidth,
height: glyphHeight,
sdfWidth: width,
sdfHeight: height,
top: top,
left: 0,
advance: advance
advance: advance,
fontAscent: textMetrics.fontBoundingBoxAscent
}
};
};
Expand Down

0 comments on commit 304b377

Please sign in to comment.