Skip to content

Set pango language through ctx.lang #2526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 17, 2025
Merged

Conversation

mapmeld
Copy link
Contributor

@mapmeld mapmeld commented Aug 2, 2025

This would set pango's language through the Canvas context ( ctx.lang, docs: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lang )

My goal was to fix issues where the same Unicode codepoint should appear differently in Simplified Chinese, Traditional Chinese, and Japanese (as an example: lang=zh vs. lang=ja ). This can be done with language-specific fonts, but modern fonts often support all options and use the lang tag.
Han unification: https://en.wikipedia.org/wiki/Han_unification
Related issue for Chrome client-side canvas: mapbox/tiny-sdf#58

I'm submitting the code and test as a draft PR because this is still failing to change the output.
I did rebuild bindings, and tried with and without pango_cairo_update_layout.
Other ideas: this is failing to set the language, setting it at the wrong time, the fonts or something needs to be reset, or pango handles Han unification using something else? I'm a longtime node-canvas user but new to the internals.
I found this reference to PANGO_LANGUAGE and %PANGO_SCRIPT_HAN https://github.com/gtk-rs/gir-files/blob/main/Pango-1.0.gir#L11631

*/
Napi::Value
Context2d::GetLanguage(const Napi::CallbackInfo& info) {
return Napi::String::New(env, state->lang);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this call pango_context_get_language() for consistency with PANGO_LAYOUT_GET_METRICS? This would avoid the need to maintain lang as parallel state in canvas_state_t.

pango_context_get_language(pango_layout_get_context(LAYOUT)))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, done ✅

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the second commit, I don't think ctx.save() and ctx.restore() will update ctx.lang, will it? It needs to be on the canvas_state_t.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, should PANGO_LAYOUT_GET_METRICS use the lang field instead of pango_context_get_language()?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The layout should be up-to-date there, but good call looking at that. I'll start a review with my thoughts...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe the better way to get the language before it is lazily committed?

if (state->lang == "") { // unchanged
  pango_context_get_language()
} else {
  pango_language_from_string(state->lang)
}

@chearon
Copy link
Collaborator

chearon commented Aug 17, 2025

@mapmeld this does seem to work (using Source Han Sans, Super OTC):

font
source (change examples/font.js with this)
const fs = require('fs')
const path = require('path')
const Canvas = require('..')

const canvas = Canvas.createCanvas(320, 320)
const ctx = canvas.getContext('2d')

ctx.lang = 'zh'
ctx.font = '50px Source Hans Sans'
ctx.fillText('\u8FD4', 0, 70, 100)

ctx.lang = 'zh-HK'
ctx.font = '50px Source Han Sans'
ctx.fillText('\u8FD4', 0, 140)

ctx.lang = 'tc'
ctx.font = '50px Source Han Sans'
ctx.fillText('\u8FD4', 0, 210)

canvas.createPNGStream().pipe(fs.createWriteStream(path.join(__dirname, 'font.png')))

My impression has been that usually different fonts are shipped for different languages, but this should definitely be used more.

Copy link
Collaborator

@chearon chearon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to also update the CHANGELOG.md,

@mapmeld mapmeld marked this pull request as ready for review August 17, 2025 15:30
@chearon
Copy link
Collaborator

chearon commented Aug 17, 2025

Update on this comment:

My impression has been that usually different fonts are shipped for different languages, but this should definitely be used more.

I forgot that there are 2 ways lang works:

  1. Font selection, wherein the language is used to remove other languages from a matching set of fonts from a family
  2. The language is also an argument to the shaper. You can have a single font face that supports glyph switching through GSUB tables. I think that's what you're referring to in the OP.

I just tested that "fi" won't turn into a ligature with EB Garamond, and the language is set to Turkish. So (2) is definitely fixed. I'm not sure if the Source Han Sans test was (1) or (2). But if (2) works, I assume Pango would do (1) as well, so I'll call it working...

@chearon chearon merged commit 6ce963d into Automattic:master Aug 17, 2025
@chearon
Copy link
Collaborator

chearon commented Aug 17, 2025

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants