[HarfBuzz] Ligatures and color changes
Jonathan Kew
jfkthame at googlemail.com
Tue Feb 19 15:09:48 PST 2013
On 19/2/13 22:34, Behdad Esfahbod wrote:
> Hi Lóránt,
>
> On 02/19/2013 12:20 PM, Lóránt Pintér wrote:
>> Hi,
>>
>> I have a problem with half-colored ligatures, like "(5) mfim" in the image:
>
> Right. That's one of the harder issues of text rendering.
>
>> I figured out two ways to do this, but neither is good enough:
>>
>> * I can shape each color range separately, but then I lose the kerning
>> between them, breaking (6)
>
> Yes. Best to not do this.
>
>> * I can tell HarfBuzz to disable ligatures for the last of the first
>> character of each color range, but then it breaks (2) or (3) and (4).
>
> Right. This is a limitation of HarfBuzz currently, that you can't turn off a
> pair-wise feature on one pair only, since changing the "liga" bit on one
> character affects it in both directions.
>
> I haven't been able to find a satisfactory fix for this yet. I'll think about it.
In general, I don't think it's clear exactly how these sort of "edge
cases" ought to work.
Suppose you have a glyph sequence A X B, and the 'liga' feature is
enabled for A and B, but not for X; but further suppose that X is a mark
glyph, the liga lookup ignores marks, and there's an AB ligature. Should
it be applied here?
Another possible approach to "disabling" ligatures at the color change -
given that harfbuzz doesn't know anything about color, that must be
something that your application is maintaining - might be to insert a
ZWNJ character at that position in the text. With the latest harfbuzz
code, I believe kerning would still apply correctly across this, but it
should prevent the ligature.
>> Is there maybe a way to tell HarfBuzz to ignore ligatures if they span that
>> color boundary? Or is there maybe a way to (quickly) assess if "liga" would be
>> applied to a range of characters?
>
> We don't have a good answer for this right now. The way I want to eventually
> fix this in Pango is different: it is to pain the ligature glyph half in each
> color. I think you can do the same using <canvas>. Just use a gradient with
> a sharp color switch for the ligature. It's a royal pain, but I think that's
> the most desirable rendering. I may be wrong.
It's a reasonable rendering for typical Latin ligatures in "simple" text
fonts. It doesn't work so well for more cursive cases. E.g. using this
approach to color the middle "f" of Zapfino's "ffi" will look rather
weird, as will coloring the parts of Arabic lam-meem-hah in a font with
"stacked" ligature forms.
>
> As for *where* to cut the ligature, here's what you need:
>
> * Count the number of cursor positions *inside* the ligature. For the "fi"
> ligature it's one. And we have one cursor position before the ligature, so in
> this case we need to cut it in two pieces,
>
> * The common heuristic then is to cut the advance width of the ligature
> (well, cluster really) into two equal pieces. If you want to be fancy, you
> can call hb_ot_layout_get_ligature_carets(), and if the number of carets
> matches what you expect (1 in this case I believe?), you can use the returned
> caret positions instead of equally dividing the ligature. I haven't seen
> anyone implementing this though, as it gives very marginal improvements over
> the heuristic.
Particularly as I suspect that relatively few fonts actually have GDEF
tables that define ligature-caret positions with any more care than
simply dividing up the advance width into equal parts.
JK
More information about the HarfBuzz
mailing list