Closed dhardy closed 3 years ago
Also @manuel-rhdt as the author of harfbuzz_rs might be willing to take a quick look?
I store a Face and create a Font on each use
hb_font_create
is esentually free. hb_face_create
is the expensive one.
since I only know the size at time of usage
You can change font size at runtime.
HarfBuzz apparently doesn't report the text index of each glyph?
Yes, it's cluster
.
You can change font size at runtime.
Not without mutable storage, which I don't have. But good to know that hb_font_create
is fast.
Yes, it's cluster.
So simple? I initially tried cluster
and codepoint
the other way around :facepalm:
Thanks!
codepoint
becomes glyph_id
after shaping. It's an optimization that hb uses. A bit confusing, I agree.
Regarding the 1 / 128
factor: do you happen to know if that is correct?
Not sure what 128 should mean, but it should be font_size/units_per_em
(harfbuzz_rs::Face::upem
). Assuming you're not setting the font size manually.
Different fonts have different units_per_em. In resvg, I'm not setting the font size at all, e.g. using the "font units" during shaping. And scaling everything to required "font size" later manually.
I'm not clear on the difference between font size and PPEM. Is it to do with hints for small font sizes?
But the factor I was talking about concerns the x_advance
output (and co.). It's necessary to put the glyphs next to each other.
Is it to do with hints for small font sizes?
HarfBuzz doesn't do hinting.
x_advance
depends on a font size. If you are not setting the font size, hb will use font units (units_per_em
). Otherwise it will scale the advance and offset values respectively.
Aha, so I should set font_size
not ppem
, then I don't need the scale factor. I guess that makes more sense? Glyphs seem a bit spaced out. I wish there was clear documentation of units (both HarfBuzz and glyph-brush).
I think hb_font_set_scale
is what you're looking for.
No, what I'm looking for is units, partly to match between libs and partly to be able to expose standard units for font sizes.
Putting this together, an 'M' in 10-point font on a 96-DPI screen should be 13.333 pixels wide. Seems to check out.
ab-glyph
uses just PxScale
, which is the "scale in pixels". If I set this to 42 and use my handy screen-ruler, an 'M' is significantly smaller than 42 pixels wide (with both serif and sans-serif fonts, more-so with the latter). Reading the code, PxScale
is just a multiplier on the font measures exposed by ttf-parser
, which also don't have units specified. Since the latter's your code @RazrFalcon I'm guessing you know the answer?
HarfBuzz exposes three methods:
hb_font_set_ppem
: set the "points per em" (integer)hb_font_set_ptem
: set the font size in points (float)hb_font_set_scale
: this takes an integer, so it can't use the (DPI * DTP) (points per pixel) value above — but perhaps it can if multiplied by a constant which is later divided from x_advance
etc.I don't understand why the first two are different, given the usual definition of point-size for a font. Maybe I need to look at some more code...
ttf-parser
doesn't support font size at all. Everything is in font units, aka units per em.
HarfBuzz exposes three methods
Just look at the sources. First two doesn't do anything you are expecting.
@dhardy this is how hb-shape
's --font-size
option works:
Right, I missed a concept: fonts have an embedded unit. Also, it seems that when HB says "pixel" it doesn't always mean "pixel" thanks to the Apple Retina malarkey.
Also, the docs specify that "ppem" is "pixels per em". There seems to be a special case when this is zero. And "many fonts enable and disable hints based on the size it is used at, so setting this is important for font objects".
This lets me guess that x_scale
has units "X per font-unit" where X is the same units as x_advance
(thus can be 1 pixel or can be more for sub-pixel precision).
Okay, after sorting out the font units for ab-glyph, things line up properly. But I still don't quite get the HB methods:
set_scale
with my factor (pixels / em) and don't set anything else, it works, but..x_advance
I don't quite get the same result: i.e. this now respects sub-pixel precision (how much of this is a good thing is another question)set_scale(1, 1)
then requires a completely different divisor to x_advance
(somewhere around 100 I guess, didn't test)ppem
is used during raster glyphs processing and hinting (not the rendering one). It doesn't affect x_advance
dramatically. Only set_scale
does.
The formula is x_advance * (font_size / units_per_em)
Indeed, setting ppem
doesn't have much visible effect. I'll just leave it unset then not knowing what to set it to?
The formula is x_advance * (font_size / units_per_em)
Only if I set set_scale(units_per_em, units_per_em)
. I guess this makes sense to use units_per_em
for the sub-pixel precision, but it is overkill. A smaller scale such as 4
would be mostly the same visually while limiting the number of sub-pixel offsets for glyphs (potentially improving glyph caching).
Only if I set set_scale(units_per_em, units_per_em).
Yes, which is default.
Alright, thanks for the help @RazrFalcon!
Next up will probably be BIDI processing, then fixes for left/right navigation, then font formatting. Still a lot to do but at least it seems I don't need to worry about font fallbacks (well, works for me)!
@RazrFalcon @alexheretic I wonder if you could help me with this?
This code partly works (using glyph-brush to do the drawing). It does do shaping and lay out a line of text which seems okay (though I haven't implemented BIDI yet).
Questions:
Face
and create aFont
on each use, since I only know the size at time of usage. Seems to work; I don't know whether there will be perf. issues later.f32
; HarfBuzz usesu32
(couldn't find the unit): dividing by 128 seems to work (or may be a little dense); dividing by 100 was a bit too spaced out.