Skip to content

Commit bbce6a4

Browse files
committed
Fix actualBoundingBoxLeft/Right with center/right alignment
This bug goes back 10 years to the original implementation. Fixes #1909
1 parent 561d933 commit bbce6a4

File tree

4 files changed

+51
-7
lines changed

4 files changed

+51
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ project adheres to [Semantic Versioning](http://semver.org/).
1010
### Changed
1111
### Added
1212
### Fixed
13+
* Fix `actualBoundingBoxLeft` and `actualBoundingBoxRight` when `textAlign='center'` or `'right'` ([#1909](https://github.com/Automattic/node-canvas/issues/1909))
1314

1415
2.10.0
1516
==================

src/CanvasRenderingContext2d.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,7 +2748,7 @@ NAN_METHOD(Context2d::MeasureText) {
27482748
double x_offset;
27492749
switch (context->state->textAlignment) {
27502750
case 0: // center
2751-
x_offset = logical_rect.width / 2;
2751+
x_offset = logical_rect.width / 2.;
27522752
break;
27532753
case 1: // right
27542754
x_offset = logical_rect.width;
@@ -2766,10 +2766,10 @@ NAN_METHOD(Context2d::MeasureText) {
27662766
Nan::New<Number>(logical_rect.width)).Check();
27672767
Nan::Set(obj,
27682768
Nan::New<String>("actualBoundingBoxLeft").ToLocalChecked(),
2769-
Nan::New<Number>(x_offset - PANGO_LBEARING(ink_rect))).Check();
2769+
Nan::New<Number>(PANGO_LBEARING(ink_rect) + x_offset)).Check();
27702770
Nan::Set(obj,
27712771
Nan::New<String>("actualBoundingBoxRight").ToLocalChecked(),
2772-
Nan::New<Number>(x_offset + PANGO_RBEARING(ink_rect))).Check();
2772+
Nan::New<Number>(PANGO_RBEARING(ink_rect) - x_offset)).Check();
27732773
Nan::Set(obj,
27742774
Nan::New<String>("actualBoundingBoxAscent").ToLocalChecked(),
27752775
Nan::New<Number>(y_offset + PANGO_ASCENT(ink_rect))).Check();

test/canvas.test.js

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ const {
2020
deregisterAllFonts
2121
} = require('../')
2222

23+
function assertApprox(actual, expected, tol) {
24+
assert(Math.abs(expected - actual) <= tol,
25+
"Expected " + actual + " to be " + expected + " +/- " + tol);
26+
}
27+
2328
describe('Canvas', function () {
2429
// Run with --expose-gc and uncomment this line to help find memory problems:
2530
// afterEach(gc);
@@ -946,20 +951,46 @@ describe('Canvas', function () {
946951
let metrics = ctx.measureText('Alphabet')
947952
// Actual value depends on font library version. Have observed values
948953
// between 0 and 0.769.
949-
assert.ok(metrics.alphabeticBaseline >= 0 && metrics.alphabeticBaseline <= 1)
954+
assertApprox(metrics.alphabeticBaseline, 0.5, 0.5)
950955
// Positive = going up from the baseline
951956
assert.ok(metrics.actualBoundingBoxAscent > 0)
952957
// Positive = going down from the baseline
953-
assert.ok(metrics.actualBoundingBoxDescent > 0) // ~4-5
958+
assertApprox(metrics.actualBoundingBoxDescent, 5, 2)
954959

955960
ctx.textBaseline = 'bottom'
956961
metrics = ctx.measureText('Alphabet')
957962
assert.strictEqual(ctx.textBaseline, 'bottom')
958-
assert.ok(metrics.alphabeticBaseline > 0) // ~4-5
963+
assertApprox(metrics.alphabeticBaseline, 5, 2)
959964
assert.ok(metrics.actualBoundingBoxAscent > 0)
960965
// On the baseline or slightly above
961966
assert.ok(metrics.actualBoundingBoxDescent <= 0)
962967
})
968+
969+
it('actualBoundingBox is correct for left, center and right alignment (#1909)', function () {
970+
const canvas = createCanvas(0, 0)
971+
const ctx = canvas.getContext('2d')
972+
973+
// positive actualBoundingBoxLeft indicates a distance going left from the
974+
// given alignment point.
975+
976+
// positive actualBoundingBoxRight indicates a distance going right from
977+
// the given alignment point.
978+
979+
ctx.textAlign = 'left'
980+
const lm = ctx.measureText('aaaa')
981+
assertApprox(lm.actualBoundingBoxLeft, -1, 4)
982+
assertApprox(lm.actualBoundingBoxRight, 21, 4)
983+
984+
ctx.textAlign = 'center'
985+
const cm = ctx.measureText('aaaa')
986+
assertApprox(cm.actualBoundingBoxLeft, 9, 4)
987+
assertApprox(cm.actualBoundingBoxRight, 11, 4)
988+
989+
ctx.textAlign = 'right'
990+
const rm = ctx.measureText('aaaa')
991+
assertApprox(rm.actualBoundingBoxLeft, 19, 4)
992+
assertApprox(rm.actualBoundingBoxRight, 1, 4)
993+
})
963994
})
964995

965996
it('Context2d#fillText()', function () {

test/public/tests.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2658,7 +2658,8 @@ tests['measureText()'] = function (ctx) {
26582658
const metrics = ctx.measureText(text)
26592659
ctx.strokeStyle = 'blue'
26602660
ctx.strokeRect(
2661-
x - metrics.actualBoundingBoxLeft + 0.5,
2661+
// positive numbers for actualBoundingBoxLeft indicate a distance going left
2662+
x + metrics.actualBoundingBoxLeft + 0.5,
26622663
y - metrics.actualBoundingBoxAscent + 0.5,
26632664
metrics.width,
26642665
metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
@@ -2677,8 +2678,19 @@ tests['measureText()'] = function (ctx) {
26772678
drawWithBBox('Alphabet bottom', 20, 90)
26782679

26792680
ctx.textBaseline = 'alphabetic'
2681+
ctx.save()
26802682
ctx.rotate(Math.PI / 8)
26812683
drawWithBBox('Alphabet', 50, 100)
2684+
ctx.restore()
2685+
2686+
ctx.textAlign = 'center'
2687+
drawWithBBox('Centered', 100, 195)
2688+
2689+
ctx.textAlign = 'left'
2690+
drawWithBBox('Left', 10, 195)
2691+
2692+
ctx.textAlign = 'right'
2693+
drawWithBBox('right', 195, 195)
26822694
}
26832695

26842696
tests['image sampling (#1084)'] = function (ctx, done) {

0 commit comments

Comments
 (0)