Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b21560e

Browse files
committedJan 14, 2025·
support ctx.direction and textAlign start/end
1 parent 0b2edc1 commit b21560e

5 files changed

+45
-12
lines changed
 

‎index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ export class CanvasRenderingContext2D {
290290
textBaseline: CanvasTextBaseline;
291291
textAlign: CanvasTextAlign;
292292
canvas: Canvas;
293+
direction: 'ltr' | 'rtl';
293294
}
294295

295296
export class CanvasGradient {

‎src/Canvas.h

-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ enum text_align_t : int8_t {
3737
TEXT_ALIGNMENT_LEFT = -1,
3838
TEXT_ALIGNMENT_CENTER = 0,
3939
TEXT_ALIGNMENT_RIGHT = 1,
40-
// Currently same as LEFT and RIGHT without RTL support:
4140
TEXT_ALIGNMENT_START = -2,
4241
TEXT_ALIGNMENT_END = 2
4342
};

‎src/CanvasRenderingContext2d.cc

+40-8
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ Context2d::Initialize(Napi::Env& env, Napi::Object& exports) {
161161
InstanceAccessor<&Context2d::GetStrokeStyle, &Context2d::SetStrokeStyle>("strokeStyle", napi_default_jsproperty),
162162
InstanceAccessor<&Context2d::GetFont, &Context2d::SetFont>("font", napi_default_jsproperty),
163163
InstanceAccessor<&Context2d::GetTextBaseline, &Context2d::SetTextBaseline>("textBaseline", napi_default_jsproperty),
164-
InstanceAccessor<&Context2d::GetTextAlign, &Context2d::SetTextAlign>("textAlign", napi_default_jsproperty)
164+
InstanceAccessor<&Context2d::GetTextAlign, &Context2d::SetTextAlign>("textAlign", napi_default_jsproperty),
165+
InstanceAccessor<&Context2d::GetDirection, &Context2d::SetDirection>("direction", napi_default_jsproperty)
165166
});
166167

167168
exports.Set("CanvasRenderingContext2d", ctor);
@@ -762,6 +763,27 @@ Context2d::AddPage(const Napi::CallbackInfo& info) {
762763
cairo_pdf_surface_set_size(canvas()->surface(), width, height);
763764
}
764765

766+
/*
767+
* Get text direction.
768+
*/
769+
Napi::Value
770+
Context2d::GetDirection(const Napi::CallbackInfo& info) {
771+
return Napi::String::New(env, state->direction);
772+
}
773+
774+
/*
775+
* Set text direction.
776+
*/
777+
void
778+
Context2d::SetDirection(const Napi::CallbackInfo& info, const Napi::Value& value) {
779+
if (!value.IsString()) return;
780+
781+
std::string dir = value.As<Napi::String>();
782+
if (dir != "ltr" && dir != "rtl") return;
783+
784+
state->direction = dir;
785+
}
786+
765787
/*
766788
* Put image data.
767789
*
@@ -2451,6 +2473,9 @@ Context2d::paintText(const Napi::CallbackInfo&info, bool stroke) {
24512473
pango_layout_set_text(layout, str.c_str(), -1);
24522474
pango_cairo_update_layout(context(), layout);
24532475

2476+
PangoDirection pango_dir = state->direction == "ltr" ? PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL;
2477+
pango_context_set_base_dir(pango_layout_get_context(_layout), pango_dir);
2478+
24542479
if (argsNum == 3) {
24552480
scaled_by = get_text_scale(layout, args[2]);
24562481
cairo_save(context());
@@ -2522,18 +2547,26 @@ inline double getBaselineAdjustment(PangoLayout* layout, short baseline) {
25222547
void
25232548
Context2d::setTextPath(double x, double y) {
25242549
PangoRectangle logical_rect;
2550+
text_align_t alignment = state->textAlignment;
25252551

2526-
switch (state->textAlignment) {
2552+
// Convert start/end to left/right based on direction
2553+
if (alignment == TEXT_ALIGNMENT_START) {
2554+
alignment = (state->direction == "rtl") ? TEXT_ALIGNMENT_RIGHT : TEXT_ALIGNMENT_LEFT;
2555+
} else if (alignment == TEXT_ALIGNMENT_END) {
2556+
alignment = (state->direction == "rtl") ? TEXT_ALIGNMENT_LEFT : TEXT_ALIGNMENT_RIGHT;
2557+
}
2558+
2559+
switch (alignment) {
25272560
case TEXT_ALIGNMENT_CENTER:
25282561
pango_layout_get_pixel_extents(_layout, NULL, &logical_rect);
25292562
x -= logical_rect.width / 2;
25302563
break;
2531-
case TEXT_ALIGNMENT_END:
25322564
case TEXT_ALIGNMENT_RIGHT:
25332565
pango_layout_get_pixel_extents(_layout, NULL, &logical_rect);
25342566
x -= logical_rect.width;
25352567
break;
2536-
default: ;
2568+
default: // TEXT_ALIGNMENT_LEFT
2569+
break;
25372570
}
25382571

25392572
y -= getBaselineAdjustment(_layout, state->textBaseline);
@@ -2687,13 +2720,12 @@ Napi::Value
26872720
Context2d::GetTextAlign(const Napi::CallbackInfo& info) {
26882721
const char* align;
26892722
switch (state->textAlignment) {
2690-
default:
2691-
// TODO the default is supposed to be "start"
26922723
case TEXT_ALIGNMENT_LEFT: align = "left"; break;
2693-
case TEXT_ALIGNMENT_START: align = "start"; break;
2694-
case TEXT_ALIGNMENT_CENTER: align = "center"; break;
26952724
case TEXT_ALIGNMENT_RIGHT: align = "right"; break;
2725+
case TEXT_ALIGNMENT_CENTER: align = "center"; break;
2726+
case TEXT_ALIGNMENT_START: align = "start"; break;
26962727
case TEXT_ALIGNMENT_END: align = "end"; break;
2728+
default: align = "start";
26972729
}
26982730
return Napi::String::New(env, align);
26992731
}

‎src/CanvasRenderingContext2d.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ struct canvas_state_t {
3131
cairo_filter_t patternQuality = CAIRO_FILTER_GOOD;
3232
float globalAlpha = 1.f;
3333
int shadowBlur = 0;
34-
text_align_t textAlignment = TEXT_ALIGNMENT_LEFT; // TODO default is supposed to be START
34+
text_align_t textAlignment = TEXT_ALIGNMENT_START;
3535
text_baseline_t textBaseline = TEXT_BASELINE_ALPHABETIC;
3636
canvas_draw_mode_t textDrawingMode = TEXT_DRAW_PATHS;
3737
bool imageSmoothingEnabled = true;
38+
std::string direction = "ltr";
3839

3940
canvas_state_t() {
4041
fontDescription = pango_font_description_from_string("sans");
@@ -182,6 +183,8 @@ class Context2d : public Napi::ObjectWrap<Context2d> {
182183
void BeginTag(const Napi::CallbackInfo& info);
183184
void EndTag(const Napi::CallbackInfo& info);
184185
#endif
186+
Napi::Value GetDirection(const Napi::CallbackInfo& info);
187+
void SetDirection(const Napi::CallbackInfo& info, const Napi::Value& value);
185188
inline void setContext(cairo_t *ctx) { _context = ctx; }
186189
inline cairo_t *context(){ return _context; }
187190
inline Canvas *canvas(){ return _canvas; }

‎test/canvas.test.js

-2
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,6 @@ describe('Canvas', function () {
569569
const canvas = createCanvas(200, 200)
570570
const ctx = canvas.getContext('2d')
571571

572-
assert.equal('left', ctx.textAlign) // default TODO wrong default
573-
ctx.textAlign = 'start'
574572
assert.equal('start', ctx.textAlign)
575573
ctx.textAlign = 'center'
576574
assert.equal('center', ctx.textAlign)

0 commit comments

Comments
 (0)
Please sign in to comment.