diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb978ce9..af2da3fe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ project adheres to [Semantic Versioning](http://semver.org/). * Fix fetching prebuilds during installation on certain newer versions of Node (#2497) * Fixed issue with fillText that was breaking subsequent fillText calls (#2171) * Fix svg rendering when the image is resized (#2498) +* Fix measureText with direction rtl textAlign start/end 3.1.0 ================== diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 06c31df75..15c5c80f5 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -2557,6 +2557,20 @@ inline double getBaselineAdjustment(PangoLayout* layout, short baseline) { } } +text_align_t +Context2d::resolveTextAlignment() { + text_align_t alignment = state->textAlignment; + + // Convert start/end to left/right based on direction + if (alignment == TEXT_ALIGNMENT_START) { + return (state->direction == "rtl") ? TEXT_ALIGNMENT_RIGHT : TEXT_ALIGNMENT_LEFT; + } else if (alignment == TEXT_ALIGNMENT_END) { + return (state->direction == "rtl") ? TEXT_ALIGNMENT_LEFT : TEXT_ALIGNMENT_RIGHT; + } + + return alignment; +} + /* * Set text path for the string in the layout at (x, y). * This function is called by paintText and won't behave correctly @@ -2567,14 +2581,7 @@ inline double getBaselineAdjustment(PangoLayout* layout, short baseline) { void Context2d::setTextPath(double x, double y) { PangoRectangle logical_rect; - text_align_t alignment = state->textAlignment; - - // Convert start/end to left/right based on direction - if (alignment == TEXT_ALIGNMENT_START) { - alignment = (state->direction == "rtl") ? TEXT_ALIGNMENT_RIGHT : TEXT_ALIGNMENT_LEFT; - } else if (alignment == TEXT_ALIGNMENT_END) { - alignment = (state->direction == "rtl") ? TEXT_ALIGNMENT_LEFT : TEXT_ALIGNMENT_RIGHT; - } + text_align_t alignment = resolveTextAlignment(); switch (alignment) { case TEXT_ALIGNMENT_CENTER: @@ -2816,16 +2823,16 @@ Context2d::MeasureText(const Napi::CallbackInfo& info) { metrics = PANGO_LAYOUT_GET_METRICS(layout); + text_align_t alignment = resolveTextAlignment(); + double x_offset; - switch (state->textAlignment) { + switch (alignment) { case TEXT_ALIGNMENT_CENTER: x_offset = logical_rect.width / 2.; break; - case TEXT_ALIGNMENT_END: case TEXT_ALIGNMENT_RIGHT: x_offset = logical_rect.width; break; - case TEXT_ALIGNMENT_START: case TEXT_ALIGNMENT_LEFT: default: x_offset = 0.0; diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 6b29b60f0..341e5936d 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -222,6 +222,7 @@ class Context2d : public Napi::ObjectWrap { void _setStrokePattern(Napi::Value arg); void checkFonts(); void paintText(const Napi::CallbackInfo&, bool); + text_align_t resolveTextAlignment(); Napi::Reference _fillStyle; Napi::Reference _strokeStyle; Canvas *_canvas; diff --git a/test/canvas.test.js b/test/canvas.test.js index b45382a2a..01156d089 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -1026,6 +1026,39 @@ describe('Canvas', function () { assertApprox(rm.actualBoundingBoxLeft, 19, 6) assertApprox(rm.actualBoundingBoxRight, 1, 6) }) + + it('resolves text alignment wrt Context2d#direction #2508', function () { + const canvas = createCanvas(0, 0) + const ctx = canvas.getContext('2d') + + ctx.textAlign = "left"; + const leftMetrics = ctx.measureText('hello'); + assert(leftMetrics.actualBoundingBoxLeft < leftMetrics.actualBoundingBoxRight, "leftMetrics.actualBoundingBoxLeft < leftMetrics.actualBoundingBoxRight"); + + ctx.textAlign = "right"; + const rightMetrics = ctx.measureText('hello'); + assert(rightMetrics.actualBoundingBoxLeft > rightMetrics.actualBoundingBoxRight, "metrics.actualBoundingBoxLeft > metrics.actualBoundingBoxRight"); + + ctx.textAlign = "start"; + + ctx.direction = "ltr"; + const ltrStartMetrics = ctx.measureText('hello'); + assert.deepStrictEqual(ltrStartMetrics, leftMetrics, "ltr start metrics should equal left metrics"); + + ctx.direction = "rtl"; + const rtlStartMetrics = ctx.measureText('hello'); + assert.deepStrictEqual(rtlStartMetrics, rightMetrics, "rtl start metrics should equal right metrics"); + + ctx.textAlign = "end"; + + ctx.direction = "ltr"; + const ltrEndMetrics = ctx.measureText('hello'); + assert.deepStrictEqual(ltrEndMetrics, rightMetrics, "ltr end metrics should equal right metrics"); + + ctx.direction = "rtl"; + const rtlEndMetrics = ctx.measureText('hello'); + assert.deepStrictEqual(rtlEndMetrics, leftMetrics, "rtl end metrics should equal left metrics"); + }) }) it('Context2d#fillText()', function () {