Replaced Freetype with harfbuzz font support#199
Replaced Freetype with harfbuzz font support#199JCash wants to merge 7 commits intoHOST-Oman:mainfrom
Conversation
|
Nice. Thanks for working on this. |
| if (run->font) | ||
| hb_font_destroy (run->font); | ||
|
|
There was a problem hiding this comment.
All font management is handled outside of the library.
There was a problem hiding this comment.
We should reference the font passed to us. We can’t depend on the client not destroying the font under our feet.
There was a problem hiding this comment.
While I'm happy do keep it for you, I would personally argue to keep the duties separate.
The font isn't really belonging to this library, but to harfbuzz.
As such I think it's reasonable to put that effort of resource management on the developer.
There was a problem hiding this comment.
We are using the font, so it is our responsibility to keep a reference to it. HarfBuzz objects are reference counted, so the whoever using the object has to make sure to reference while using and destroy when done (destroy doe not immediately free the object, it decreases the reference count and only frees when it is zero).
|
|
||
| #include <assert.h> | ||
| #include <string.h> | ||
| #include <stdlib.h> |
|
|
||
| #ifdef RAQM_TESTING | ||
| #include <stdio.h> | ||
| #include <hb-ot.h> // for family name |
There was a problem hiding this comment.
Only rely on hb-ot in testing mode, as the user may have built harbuzz without that support.
| typedef struct _font_data | ||
| { | ||
| hb_blob_t *blob; | ||
| hb_face_t *face; | ||
| hb_font_t *font; | ||
| void *data; | ||
| struct _font_data* next; | ||
| } font_data_t; |
There was a problem hiding this comment.
Easy structure to keep track of the created data.
There was a problem hiding this comment.
Is the blob for the face? Is it needed after face creation? If not, it can be destroyed and let face manage lifetime. Same about keeping face around, can it be fetched from font as needed? Sorry, my knowledge of raqm code is non-existent.
There was a problem hiding this comment.
Thanks!
You are correct, the blob is only for the face creation. and it's my knowledge about HB that is non-existent :)
There was a problem hiding this comment.
More than happy to help!
All HB objects do lifecycle management, as you would expect.
If you ever need it, they also have [sg]et_user_data that allows attaching arbitrary data to them, to be destructed when the object is winding down.
| static font_data_t* | ||
| load_font(const char* path) | ||
| { | ||
| size_t fontdata_size; | ||
| font_data_t *font = (font_data_t*)malloc(sizeof(font_data_t)); | ||
| font->next = 0; | ||
| font->data = read_file(path, &fontdata_size); | ||
| assert (font->data != 0); | ||
|
|
||
| font->blob = hb_blob_create(font->data, fontdata_size, HB_MEMORY_MODE_READONLY, 0, 0); | ||
| assert (font->blob != 0); | ||
| font->face = hb_face_create(font->blob, 0); | ||
| assert (font->face != 0); | ||
| font->font = hb_font_create(font->face); | ||
| assert (font->font != 0); | ||
|
|
||
| return font; | ||
| } |
There was a problem hiding this comment.
Showing users how one would create and use a hb_font_t from memory.
| * raqm_get_glyphs(). | ||
| */ | ||
| typedef struct raqm_glyph_t { | ||
| hb_font_t* hbfont; |
There was a problem hiding this comment.
structure size opt: putting the large pointer first in the structure.
There was a problem hiding this comment.
This changes the API. The bigger question is how we handle this without breaking both the API and ABI? I don’t have any good ideas.
There was a problem hiding this comment.
I don't think there's use case of using both api's at the same time, I would opt to use the ifdef like so:
typedef struct
{
#ifdef RAQM_FREETYPE
FT_Face ftface;
int ftloadflags;
#else
hb_font_t *hbfont;
#endif
What do you think?
There was a problem hiding this comment.
I’m fine with an approach like this.
There was a problem hiding this comment.
structure size opt: putting the large pointer first in the structure.
In this case I don't think it matters, since there's an even number of ints before the pointer, so the struct size should be the same. I might be wrong.
There was a problem hiding this comment.
structure size opt: putting the large pointer first in the structure.
In this case I don't think it matters, since there's an even number of ints before the pointer, so the struct size should be the same. I might be wrong.
You are correct, there is no difference (on 64-bit or 32-bit): https://godbolt.org/z/vGTood47v
khaledhosny
left a comment
There was a problem hiding this comment.
Thanks for working on this. But I’m afraid that this is unmergable in its current state unless we are going to break the ABI and raise the major version number, which is not something I want to do just yet.
| raqm_set_freetype_face (raqm_t *rq, | ||
| FT_Face face) | ||
| { | ||
| return _raqm_set_freetype_face (rq, face, 0, rq->text_len); |
There was a problem hiding this comment.
We need keep this API.
| if (run->font) | ||
| hb_font_destroy (run->font); | ||
|
|
There was a problem hiding this comment.
We should reference the font passed to us. We can’t depend on the client not destroying the font under our feet.
| font->data = read_file(path, &fontdata_size); | ||
| assert (font->data != 0); | ||
|
|
||
| blob = hb_blob_create(font->data, fontdata_size, HB_MEMORY_MODE_READONLY, 0, 0); |
There was a problem hiding this comment.
You can use hb_blob_create_from_file_or_fail() or even hb_face_create_from_file_or_fail()
| assert (font->data != 0); | ||
|
|
||
| blob = hb_blob_create(font->data, fontdata_size, HB_MEMORY_MODE_READONLY, 0, 0); | ||
| assert (blob != 0); |
There was a problem hiding this comment.
hb_blob_create() never returns NULL (_or_fail group of functions do, though).
| * raqm_get_glyphs(). | ||
| */ | ||
| typedef struct raqm_glyph_t { | ||
| hb_font_t* hbfont; |
There was a problem hiding this comment.
This changes the API. The bigger question is how we handle this without breaking both the API and ABI? I don’t have any good ideas.
| char family[128]; | ||
| uint32_t family_name_len = sizeof(family); | ||
| hb_face_t *face = hb_font_get_face(run->font); | ||
| hb_ot_name_get_utf8 (face, HB_OT_NAME_ID_FONT_FAMILY, HB_LANGUAGE_INVALID, &family_name_len, family); |
There was a problem hiding this comment.
This deserves its own helper function.
was trying to land something like this this in libraqm with this pr: HOST-Oman#199
was trying to land something like this this in libraqm with this pr: HOST-Oman#199
Fixes: #198
It seems like it should work, however there is apparently some detail I don't understand as the
direction-ttb-2.testfails on this:It is the only test that fails, and I can't seem to pinpoint the difference between the original Freetype created font.
I tried removing
FT_Vector_Transformfrom the main branch, but that still passed all the tests on the main branch 🤔