conky icon indicating copy to clipboard operation
conky copied to clipboard

Better Text Rendering for cairo / lua

Open simotek opened this issue 3 years ago • 18 comments

Description

Introduction

I have attempted to resolve #900 by creating a new lua binding specifically for doing font rendering in Cairo using Freetype and Harfbuzz, fontconfig is also used to locate the correct fonts. I have chosen to follow the approach of the imlib2_helper binding and not expose functions from the headers of each of these libraries but rather provide simple functions that "internally" use each of these libraries.

At the time of creating this PR I have no fixed thoughts on the API other then it works for my use case and tries to balance the simple act of rendering an English string while also allowing complex options such as RTL text as requested in #75 as well as being able to center and right align text #940 and #1017. So your thoughts on the API topic would be much appreciated, once the API is finalized I will add appropriate documentation. currently this is the last major step for be before being able to move to a lua only config.

Current API Description (Happy to make changes here)

Loading a font from a file is a slow enough operation that we probably don't want to do it multiple times so I separated loading fonts and freeing memory at close into separate functions.

/* font is a string containing the name of the font to load */
/* this will be matched on a best effort basis and FontConfig will fall back to a similar font if the specified font isn't found */
FontData * cairo_text_hp_load_font(const char *font, int font_size);
void cairo_text_hp_destroy_font(FontData *font);

The next set of functions cover the "Simple" English use cases, I could have added a parameter for alignment but I was trying to keep the common Left case as simple as possible.

void cairo_text_hp_simple_show(cairo_t *cr, int x, int y, const char *text, FontData *font);
void cairo_text_hp_simple_show_center(cairo_t *cr, int x, int y, const char *text, FontData *font);
void cairo_text_hp_simple_show_right(cairo_t *cr, int x, int y, const char *text, FontData *font);

The next function is the "catch all" with the main implementation and allows tweeking of the internalization options such as text direction in Harfbuzz for people looking to use non latin languages.

/* 
 * Direction calls hb_direction_from_string example values are LTR and RTL
 *   https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-direction-from-string
 * Script is an ISO 15924 4 character string, "Zyyy" can be used for "Common" and "Zinh"
 *  for "Inherited". 
 *  https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-script-from-string
 * Language is a BCP 47 language tag. eg "en" or "en-US"
 */
void cairo_text_hp_intl_show(cairo_t *cr, int x, int y, cairo_text_alignment_t alignment, const char *text, 
                                                    FontData *font,  const char *direction, const char *script, const char *language);

Finally when doing layouting sometimes its useful to know how wide the final string will be so the following find the text width, again there is a simple latin version and an internationalized version. In the future I'll also provide a Height function which will be important for supporting vertical text.

int cairo_text_hp_simple_text_width(const char *text, FontData *font);
int cairo_text_hp_intl_text_width(const char *text, FontData *font, const char *direction, const char *script, const char *language);

Screenshot

In the following screenshot the "Cairo" text is using Cairo's built in basic text rendering, the "Conky" text is using Conky's standard text rendering and the "Freetype" strings are using this new API with Freetype and Harfbuzz rendering the text in Cairo. All these cases are just using the default settings as found on openSUSE Tumbleweed.

shot-2023-04-11_21-13-49

simotek avatar Apr 12 '23 00:04 simotek

Deploy Preview for conkyweb canceled.

Name Link
Latest commit d5d20e8004fab46a8a7789c778be399cbce42808
Latest deploy log https://app.netlify.com/sites/conkyweb/deploys/643606d387ba2c0007c0b550

netlify[bot] avatar Apr 12 '23 00:04 netlify[bot]

Thanks for the feedback, i'll update the docs and finish of implementing the Top to Bottom features then finish up a couple of configs to use them before sending through some updates. But its good to know i'm heading in the right direction.

simotek avatar Apr 17 '23 05:04 simotek

After trying this patches, bug #75 still exist!

Screenshot_٢٠٢٣٠٧٠٤_٠٣٢٨٤١

moceap avatar Jul 04 '23 00:07 moceap

After trying this patches, bug #75 still exist!

Screenshot_٢٠٢٣٠٧٠٤_٠٣٢٨٤١

Yes that is currently to be expected, the WIP patch just had the LTR support so I could get feedback on the API, RTL is almost there I just need to finish writing the tests.

Also this change only works with the lua API, however it is the first step in my project to add a toolkit to make using the lua API much simpler. Although that is further from completion.

simotek avatar Jul 06 '23 02:07 simotek

@moceap Can you confirm that the following screenshot looks ok, it should be the days of the week. shot-2023-07-20_15-27-09

I'll probably do just a little more testing of my actual real world usecases before sending through an updated pull request

simotek avatar Jul 20 '23 06:07 simotek

shot-2023-07-20_15-51-45

This one uses Noto Sans Arabic instead.

simotek avatar Jul 20 '23 06:07 simotek

No it's not OK.

Letters in Arabic should be connected:

You write:

الإثنين يوم الثلاثاء الأربعاء يوم الخميس جمعة السبت الأحد

Look at them here in the browser, they are connected.

moceap avatar Aug 09 '23 14:08 moceap

No it's not OK.

Letters in Arabic should be connected:

You write:

الإثنين يوم الثلاثاء الأربعاء يوم الخميس جمعة السبت الأحد

Look at them here in the browser, they are connected.

Thanks for the confirmation, that's what I thought i'll have to have a closer look at whats going wrong, the left to right seems to be ok.

simotek avatar Aug 10 '23 12:08 simotek

@simotek Take a look https://github.com/HOST-Oman/libraqm, It may fast the process.

moceap avatar Dec 04 '23 02:12 moceap

@simotek Take a look https://github.com/HOST-Oman/libraqm, It may fast the process.

One thing I noticed at https://github.com/HOST-Oman/libraqm/blob/9d7ca9d59dba38e777bdcd096870776dab5e6e66/src/raqm.c#L1793C1-L1793C48 is that for the RTL case they seem to have hardcoded a -1 into the calculation for character position, So I might have to have a play with that later.

It seemed like hardcoding a -1 into the width of each character would solve the issue but I didn't want to just do it without seeing it documented, but the fact this other codebase is suggests its probably the right solution

simotek avatar Dec 08 '23 00:12 simotek

Deploy Preview for conkyweb canceled.

Name Link
Latest commit e5482ca97941677973f2c44eeea1a239e3bdc115
Latest deploy log https://app.netlify.com/sites/conkyweb/deploys/65e670c2e2e84d00089e6d00

netlify[bot] avatar Feb 15 '24 01:02 netlify[bot]

So far I've done all the interface changes, other then caching fonts, which is next on my list.

As for the RTL codepaths, subtracting 1/10th of the font size seems to get much closer then -1 especially for larger font sizes. Its not perfect for all fonts at all sizes though, but is significantly better, i'll follow this up with upstream closer

@moceap I presume this screenshot is getting much closer. At this point I have no idea if the text is actual words.

shot-2024-02-15_11-53-40

simotek avatar Feb 15 '24 02:02 simotek

Also if anyone has any idea what Ubuntu packages are needed to get cmake to find freetype that would be much appreciated so that I don't need to spin up a VM and test.

simotek avatar Feb 15 '24 02:02 simotek

Also if anyone has any idea what Ubuntu packages are needed to get cmake to find freetype that would be much appreciated so that I don't need to spin up a VM and test.

Should be libfreetype6-dev, see: https://askubuntu.com/questions/1347131/what-is-the-reason-of-cmake-error-when-using-freetype2-header

  • CMake is crappy at locating dependencies sometimes (amongst a rather long list of other things), if you have that package installed, send the output of apt-file list libfreetype6-dev so we can patch the Find script.

Caellian avatar Mar 18 '24 23:03 Caellian