Skip to content
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

optimize setLanguage, setScript, shapeWithTrace #82

Merged
merged 1 commit into from
May 19, 2023

Conversation

chearon
Copy link
Contributor

@chearon chearon commented May 19, 2023

I'm seeing createCString as a dominator in a project I'm working on. Nodejs text encoding/decoding is slow: nodejs/node#39879. Browsers don't show much difference with this change.

Here's how I profiled it in harfbuzzjs:

diff --cc examples/hbjs.example.js
index b7718e9,b7718e9..75b4c3a
--- a/examples/hbjs.example.js
+++ b/examples/hbjs.example.js
@@@ -7,8 -7,8 +7,15 @@@ function example(hb, fontBlob, text) 
    font.setScale(1000, 1000); // Optional, if not given will be in font upem
  
    var buffer = hb.createBuffer();
++  console.time('c strings');
++  for (let i = 0; i < 1000; i++) {
++    buffer.setLanguage('en');
++    buffer.setScript('Latn');
++  }
++  console.timeEnd('c strings');
    buffer.addText(text || 'abc');
--  buffer.guessSegmentProperties();
++  buffer.setDirection('ltr');
++  buffer.setClusterLevel(1);
    // buffer.setDirection('ltr'); // optional as can be set by guessSegmentProperties also
    hb.shape(font, buffer); // features are not supported yet
    var result = buffer.json(font);

@chearon
Copy link
Contributor Author

chearon commented May 19, 2023

By the way, I also profiled harfbuzzjs against canvas's measureText in Chrome and Firefox yesterday. I was surprised at how well it performed. Unsurprisingly measureText is faster, but doing word wrapping that way necessarily involves measuring words individually. When you compare that to shaping whole paragraphs in harfbuzzjs, it is often only slower by a few milliseconds before the browser's shape cache kicks in (I measured ~10 paragraphs).

I've also experimented with shaping word-by-word like Firefox does, but that's too many shape() calls. Calling into WASM incurs a cost. I think if whole paragraphs were shaped until enough data is collected, then switch to shaping by word, harfbuzzjs becomes a serious choice to layout text in a canvas.

@behdad behdad requested a review from khaledhosny May 19, 2023 15:34
hbjs.js Outdated Show resolved Hide resolved
@khaledhosny
Copy link
Contributor

Thanks, the use of TextEncoder here always felt like an overkill.

@@ -329,7 +330,7 @@ function hbjs(instance) {
* @param {string} script: The buffer script
*/
setScript: function (script) {
var str = createCString(script);
var str = createAsciiString(script);
Copy link
Contributor

Choose a reason for hiding this comment

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

It probably does not matter in practice, but you can turn the string into a tag yourself and use hb_script_from_iso15924_tag()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I may try that and open a followup. I also wonder if there would be a big difference if you can pass an hb_tag directly to setScript and setLanguage (so it accepts string | number).

Nodejs text encoding/decoding is slow: nodejs/node#39879

It's faster to encode in JS. Browsers don't show much difference
with this change.
@chearon chearon force-pushed the create-c-string-optimization branch from 2563129 to 55ffd39 Compare May 19, 2023 16:48
@khaledhosny khaledhosny merged commit 78f4959 into harfbuzz:main May 19, 2023
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.

2 participants