diff --git a/CHANGELOG.md b/CHANGELOG.md index 85b51d474..085dd412f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ project adheres to [Semantic Versioning](http://semver.org/). ### Changed ### Added ### Fixed +* Fix `actualBoundingBoxLeft` and `actualBoundingBoxRight` when `textAlign='center'` or `'right'` ([#1909](https://github.com/Automattic/node-canvas/issues/1909)) 2.10.0 ================== diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 10629cee7..60a86cb3b 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -2748,7 +2748,7 @@ NAN_METHOD(Context2d::MeasureText) { double x_offset; switch (context->state->textAlignment) { case 0: // center - x_offset = logical_rect.width / 2; + x_offset = logical_rect.width / 2.; break; case 1: // right x_offset = logical_rect.width; @@ -2766,10 +2766,10 @@ NAN_METHOD(Context2d::MeasureText) { Nan::New(logical_rect.width)).Check(); Nan::Set(obj, Nan::New("actualBoundingBoxLeft").ToLocalChecked(), - Nan::New(x_offset - PANGO_LBEARING(ink_rect))).Check(); + Nan::New(PANGO_LBEARING(ink_rect) + x_offset)).Check(); Nan::Set(obj, Nan::New("actualBoundingBoxRight").ToLocalChecked(), - Nan::New(x_offset + PANGO_RBEARING(ink_rect))).Check(); + Nan::New(PANGO_RBEARING(ink_rect) - x_offset)).Check(); Nan::Set(obj, Nan::New("actualBoundingBoxAscent").ToLocalChecked(), Nan::New(y_offset + PANGO_ASCENT(ink_rect))).Check(); diff --git a/test/canvas.test.js b/test/canvas.test.js index a81de892e..bcfade057 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -20,6 +20,11 @@ const { deregisterAllFonts } = require('../') +function assertApprox(actual, expected, tol) { + assert(Math.abs(expected - actual) <= tol, + "Expected " + actual + " to be " + expected + " +/- " + tol); +} + describe('Canvas', function () { // Run with --expose-gc and uncomment this line to help find memory problems: // afterEach(gc); @@ -946,20 +951,46 @@ describe('Canvas', function () { let metrics = ctx.measureText('Alphabet') // Actual value depends on font library version. Have observed values // between 0 and 0.769. - assert.ok(metrics.alphabeticBaseline >= 0 && metrics.alphabeticBaseline <= 1) + assertApprox(metrics.alphabeticBaseline, 0.5, 0.5) // Positive = going up from the baseline assert.ok(metrics.actualBoundingBoxAscent > 0) // Positive = going down from the baseline - assert.ok(metrics.actualBoundingBoxDescent > 0) // ~4-5 + assertApprox(metrics.actualBoundingBoxDescent, 5, 2) ctx.textBaseline = 'bottom' metrics = ctx.measureText('Alphabet') assert.strictEqual(ctx.textBaseline, 'bottom') - assert.ok(metrics.alphabeticBaseline > 0) // ~4-5 + assertApprox(metrics.alphabeticBaseline, 5, 2) assert.ok(metrics.actualBoundingBoxAscent > 0) // On the baseline or slightly above assert.ok(metrics.actualBoundingBoxDescent <= 0) }) + + it('actualBoundingBox is correct for left, center and right alignment (#1909)', function () { + const canvas = createCanvas(0, 0) + const ctx = canvas.getContext('2d') + + // positive actualBoundingBoxLeft indicates a distance going left from the + // given alignment point. + + // positive actualBoundingBoxRight indicates a distance going right from + // the given alignment point. + + ctx.textAlign = 'left' + const lm = ctx.measureText('aaaa') + assertApprox(lm.actualBoundingBoxLeft, -1, 5) + assertApprox(lm.actualBoundingBoxRight, 21, 5) + + ctx.textAlign = 'center' + const cm = ctx.measureText('aaaa') + assertApprox(cm.actualBoundingBoxLeft, 9, 5) + assertApprox(cm.actualBoundingBoxRight, 11, 5) + + ctx.textAlign = 'right' + const rm = ctx.measureText('aaaa') + assertApprox(rm.actualBoundingBoxLeft, 19, 5) + assertApprox(rm.actualBoundingBoxRight, 1, 5) + }) }) it('Context2d#fillText()', function () { diff --git a/test/public/tests.js b/test/public/tests.js index 66bb14ddb..651105e36 100644 --- a/test/public/tests.js +++ b/test/public/tests.js @@ -2658,7 +2658,8 @@ tests['measureText()'] = function (ctx) { const metrics = ctx.measureText(text) ctx.strokeStyle = 'blue' ctx.strokeRect( - x - metrics.actualBoundingBoxLeft + 0.5, + // positive numbers for actualBoundingBoxLeft indicate a distance going left + x + metrics.actualBoundingBoxLeft + 0.5, y - metrics.actualBoundingBoxAscent + 0.5, metrics.width, metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent @@ -2677,8 +2678,19 @@ tests['measureText()'] = function (ctx) { drawWithBBox('Alphabet bottom', 20, 90) ctx.textBaseline = 'alphabetic' + ctx.save() ctx.rotate(Math.PI / 8) drawWithBBox('Alphabet', 50, 100) + ctx.restore() + + ctx.textAlign = 'center' + drawWithBBox('Centered', 100, 195) + + ctx.textAlign = 'left' + drawWithBBox('Left', 10, 195) + + ctx.textAlign = 'right' + drawWithBBox('right', 195, 195) } tests['image sampling (#1084)'] = function (ctx, done) {