* Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
@ 2020-05-17 10:41 Julius Pfrommer
2020-05-17 14:09 ` Arthur Miller
2020-05-17 14:35 ` Eli Zaretskii
0 siblings, 2 replies; 145+ messages in thread
From: Julius Pfrommer @ 2020-05-17 10:41 UTC (permalink / raw)
To: emacs-devel
Hi all,
during the recent discussion on "Emacs being too square", I recalled a
few projects that use OpenGL for terminal emulators [1,2]. With good
performance, smooth scrolling and the possibility to add more visual
*bling*.
I had a good look at Emacs' code-base to see if similar approaches
could be used. As you can imagine, I got lost in a forest of #ifdef for
different platforms and GUI toolkits. The code looks scary to touch. If
you don't have access to *all supported platform*, it is likely that
changes break a platform you could not test locally.
To make the code-base less scary, there should be more code-sharing
across GUI platforms. And this is indeed possible!
The GTK-based Emacs GUI can use Cairo for rendering. Cairo + FreeType +
HarfBuzz (calling it CFH for simplicity) is available for the other
supported platforms as well (besides pure TTY):
- GnuSTEP [http://wiki.gnustep.org/index.php/Backend]
- Raw Xlib [https://www.cairographics.org/Xlib/]
- Windows+MacOS [https://www.cairographics.org/download/]
Big portions of the platform-specific GUI code could be unified based on
the CFH libraries. Is a hard dependency on the CFH libraries imaginable?
Maybe one of the platforms is a "low-hanging fruit" to get things going.
As every major refactoring, there should be a series of small steps in
order to keep things stable.
Thank you for the hard work put into this amazing piece of software!
Regards, Julius
[1] https://sw.kovidgoyal.net/kitty/
[2] https://github.com/alacritty/alacritty
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 10:41 Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
@ 2020-05-17 14:09 ` Arthur Miller
2020-05-17 14:30 ` Eli Zaretskii
2020-05-17 14:35 ` Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: Arthur Miller @ 2020-05-17 14:09 UTC (permalink / raw)
To: Julius Pfrommer; +Cc: emacs-devel
Julius Pfrommer <julius.pfrommer@web.de> writes:
> Hi all,
>
> during the recent discussion on "Emacs being too square", I recalled a
> few projects that use OpenGL for terminal emulators [1,2]. With good
> performance, smooth scrolling and the possibility to add more visual
> *bling*.
>
> I had a good look at Emacs' code-base to see if similar approaches
> could be used. As you can imagine, I got lost in a forest of #ifdef for
> different platforms and GUI toolkits. The code looks scary to touch. If
> you don't have access to *all supported platform*, it is likely that
> changes break a platform you could not test locally.
I have been looking into same, some time ago and recently, and I
experience same problem. A forest of cases, all coded into same place in
giant files of 5K+ lines :-).
> To make the code-base less scary, there should be more code-sharing
> across GUI platforms. And this is indeed possible!
Emacs and Emacs src could benefit of some modularization and refactoring
definitely.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 14:09 ` Arthur Miller
@ 2020-05-17 14:30 ` Eli Zaretskii
2020-05-17 15:06 ` Arthur Miller
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 14:30 UTC (permalink / raw)
To: emacs-devel, Arthur Miller, Julius Pfrommer
On May 17, 2020 5:09:08 PM GMT+03:00, Arthur Miller <arthur.miller@live.com> wrote:
> Julius Pfrommer <julius.pfrommer@web.de> writes:
>
> > Hi all,
> >
> > during the recent discussion on "Emacs being too square", I recalled
> a
> > few projects that use OpenGL for terminal emulators [1,2]. With good
> > performance, smooth scrolling and the possibility to add more visual
> > *bling*.
> >
> > I had a good look at Emacs' code-base to see if similar approaches
> > could be used. As you can imagine, I got lost in a forest of #ifdef
> for
> > different platforms and GUI toolkits. The code looks scary to touch.
> If
> > you don't have access to *all supported platform*, it is likely that
> > changes break a platform you could not test locally.
>
> I have been looking into same, some time ago and recently, and I
> experience same problem. A forest of cases, all coded into same place
> in
> giant files of 5K+ lines :-).
>
> > To make the code-base less scary, there should be more code-sharing
> > across GUI platforms. And this is indeed possible!
> Emacs and Emacs src could benefit of some modularization and
> refactoring
> definitely.
I suggest to go through the archives and the Git logs to see how many such efforts have been made and are already in the codebase. It isn't like the advantages of this are unclear to the development team, or that nothing is being done in that direction. Far from it.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 10:41 Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
2020-05-17 14:09 ` Arthur Miller
@ 2020-05-17 14:35 ` Eli Zaretskii
2020-05-17 14:59 ` Julius Pfrommer
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 14:35 UTC (permalink / raw)
To: emacs-devel, Julius Pfrommer
On May 17, 2020 1:41:25 PM GMT+03:00, Julius Pfrommer <julius.pfrommer@web.de> wrote:
> Hi all,
>
> during the recent discussion on "Emacs being too square", I recalled a
> few projects that use OpenGL for terminal emulators [1,2]. With good
> performance, smooth scrolling and the possibility to add more visual
> *bling*.
>
> I had a good look at Emacs' code-base to see if similar approaches
> could be used. As you can imagine, I got lost in a forest of #ifdef
> for
> different platforms and GUI toolkits. The code looks scary to touch.
> If
> you don't have access to *all supported platform*, it is likely that
> changes break a platform you could not test locally.
>
> To make the code-base less scary, there should be more code-sharing
> across GUI platforms. And this is indeed possible!
>
> The GTK-based Emacs GUI can use Cairo for rendering. Cairo + FreeType
> +
> HarfBuzz (calling it CFH for simplicity) is available for the other
> supported platforms as well (besides pure TTY):
>
> - GnuSTEP [http://wiki.gnustep.org/index.php/Backend]
> - Raw Xlib [https://www.cairographics.org/Xlib/]
> - Windows+MacOS [https://www.cairographics.org/download/]
>
> Big portions of the platform-specific GUI code could be unified based
> on
> the CFH libraries. Is a hard dependency on the CFH libraries
> imaginable?
>
> Maybe one of the platforms is a "low-hanging fruit" to get things
> going.
> As every major refactoring, there should be a series of small steps in
> order to keep things stable.
>
> Thank you for the hard work put into this amazing piece of software!
>
> Regards, Julius
>
> [1] https://sw.kovidgoyal.net/kitty/
> [2] https://github.com/alacritty/alacritty
Any work in this direction is and always has been welcome. The practical problem with that is that you need to have access to all the supported platforms to make sure the refactoring works.
FWIW, I'm not sure I share your optimism regarding the Cairo way, I think it requires something from the system as well, so it might be not so easy.
And the GUI toolkits are AFAIU a separate issue, not directly related to how we draw to the glass.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 14:35 ` Eli Zaretskii
@ 2020-05-17 14:59 ` Julius Pfrommer
2020-05-17 15:55 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Julius Pfrommer @ 2020-05-17 14:59 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
Eli,
> Any work in this direction is and always has been welcome. The
> practical problem with that is that you need to have access to all
> the supported platforms to make sure the refactoring works.
>
> FWIW, I'm not sure I share your optimism regarding the Cairo way, I
> think it requires something from the system as well, so it might be
> not so easy.
>
> And the GUI toolkits are AFAIU a separate issue, not directly related
> to how we draw to the glass.
I am well aware of the effort to keep the many different platforms
alive.
Let me phrase the question differently: Would it be okay to have a hard
dependency on the Cairo+FreeType+Harfbuzz (CFH) libraries, as they are
available everywhere?
It would be a pity to invest time into a direction that is infeasible
from the outset.
Even on Linux, this would unlock quite a few simplifications. I count
at least three font handling "backends" here.
Regards, Julius
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 14:30 ` Eli Zaretskii
@ 2020-05-17 15:06 ` Arthur Miller
2020-05-17 15:56 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Arthur Miller @ 2020-05-17 15:06 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Julius Pfrommer, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
> On May 17, 2020 5:09:08 PM GMT+03:00, Arthur Miller <arthur.miller@live.com> wrote:
>> Julius Pfrommer <julius.pfrommer@web.de> writes:
>>
>> > Hi all,
>> >
>> > during the recent discussion on "Emacs being too square", I recalled
>> a
>> > few projects that use OpenGL for terminal emulators [1,2]. With good
>> > performance, smooth scrolling and the possibility to add more visual
>> > *bling*.
>> >
>> > I had a good look at Emacs' code-base to see if similar approaches
>> > could be used. As you can imagine, I got lost in a forest of #ifdef
>> for
>> > different platforms and GUI toolkits. The code looks scary to touch.
>> If
>> > you don't have access to *all supported platform*, it is likely that
>> > changes break a platform you could not test locally.
>>
>> I have been looking into same, some time ago and recently, and I
>> experience same problem. A forest of cases, all coded into same place
>> in
>> giant files of 5K+ lines :-).
>>
>> > To make the code-base less scary, there should be more code-sharing
>> > across GUI platforms. And this is indeed possible!
>> Emacs and Emacs src could benefit of some modularization and
>> refactoring
>> definitely.
>
> I suggest to go through the archives and the Git logs to see how many such
> efforts have been made and are already in the codebase. It isn't like the
> advantages of this are unclear to the development team, or that nothing is being
> done in that direction. Far from it.
I understand that, and I am conscius myself that you devs are aware of
it and that you would probably do something about it if it was less work
than it probably is. I believe you it is not easy considering the long
history of Emacs. I am just reflecting over how I feel every time I peek
into souces. It feels like I am looking into sqlite ammalgamation :-).
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 14:59 ` Julius Pfrommer
@ 2020-05-17 15:55 ` Eli Zaretskii
2020-05-17 16:28 ` Pip Cet
2020-05-17 18:28 ` Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
0 siblings, 2 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 15:55 UTC (permalink / raw)
To: Julius Pfrommer; +Cc: emacs-devel
> Date: Sun, 17 May 2020 16:59:53 +0200
> From: Julius Pfrommer <julius.pfrommer@web.de>
> Cc: emacs-devel@gnu.org
>
> Let me phrase the question differently: Would it be okay to have a hard
> dependency on the Cairo+FreeType+Harfbuzz (CFH) libraries, as they are
> available everywhere?
First, we need to establish that this is a solution, and for what
problem(s). It is important to realize that the GUI backends we use
handle much more than just drawing text, they need to be able to
display GUI widgets, frame and window decorations (menu bar, tool bar,
scroll bars, the frame title, etc.), and much more. Is the
configuration you propose capable of doing all that? I don't think
the answer will be full and definitive until "Someone" walks through
all the APIs we implement in x/w32/ns/fns.c and x/w32/ns/term.c, and
makes sure they all can be covered.
Next, please be aware that we already made the decision to use
HarfBuzz as our main text-shaping engine. X and w32 already use it;
for NS someone has to write the code (and they are not very likely to
do so because macOS users consider the native text shaping more
feature-rich). Dropping the other font backends is a matter of time,
but it could take a long time.
In any case, the font backend is not the main issue here; in
particular, the likes of FreeType are hardly even seen except on very
low level of the code. It's the other aspects of GUI code that
bothers me much more.
> Even on Linux, this would unlock quite a few simplifications. I count
> at least three font handling "backends" here.
Down to 2 and one deprecated one on master. Bu again, font backends
is a relatively easy problem, and it is being dealt with.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 15:06 ` Arthur Miller
@ 2020-05-17 15:56 ` Eli Zaretskii
2020-05-17 16:50 ` Arthur Miller
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 15:56 UTC (permalink / raw)
To: Arthur Miller; +Cc: julius.pfrommer, emacs-devel
> From: Arthur Miller <arthur.miller@live.com>
> Cc: emacs-devel@gnu.org, Julius Pfrommer <julius.pfrommer@web.de>
> Date: Sun, 17 May 2020 17:06:35 +0200
>
> I am just reflecting over how I feel every time I peek
> into souces. It feels like I am looking into sqlite ammalgamation :-).
It was worse just a year ago. It will be better a year from now.
patches are welcome.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 15:55 ` Eli Zaretskii
@ 2020-05-17 16:28 ` Pip Cet
2020-05-17 17:00 ` Eli Zaretskii
2020-05-17 18:28 ` Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
1 sibling, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-17 16:28 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel, Julius Pfrommer
On Sun, May 17, 2020 at 3:56 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > Date: Sun, 17 May 2020 16:59:53 +0200
> > From: Julius Pfrommer <julius.pfrommer@web.de>
> > Cc: emacs-devel@gnu.org
> Next, please be aware that we already made the decision to use
> HarfBuzz as our main text-shaping engine.
That's a decision that, having just played with HarfBuzz, I find
puzzling. It appears to have no practical support for treating
ligatures as anything but monolithic glyphs: is there a documented way
of getting HarfBuzz to tell you which part of the "ffi" ligature is
the middle "f"? I suspect the answer is "there are some languages
whose scripts don't allow for the equivalent operation, so we won't
support it at all, as a matter of principle".
I'm not sure PangoCairo does better, but whatever Libreoffice uses
appears to get the job done, so at least one display engine out there
solves this problem.
(This is assuming we want kerning, ligatures, and subpixel rendering
for English text. "Real" text shaping, composition, reordrant glyphs,
and bidi concerns are something that I can't really comment on, beyond
admitting that, of course, supporting the world's major languages at
all is more important than supporting English with the typographic
finesse we currently lack).
Years ago, I ran a WebAssembly version of Emacs in a web browser.
(Back then, I used a terminal emulator written in JavaScript.) I'd
certainly like to do that again some day, and I think a hard
dependency on Cairo and FreeType would make that even harder.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 15:56 ` Eli Zaretskii
@ 2020-05-17 16:50 ` Arthur Miller
2020-05-17 17:06 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Arthur Miller @ 2020-05-17 16:50 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: julius.pfrommer, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Arthur Miller <arthur.miller@live.com>
>> Cc: emacs-devel@gnu.org, Julius Pfrommer <julius.pfrommer@web.de>
>> Date: Sun, 17 May 2020 17:06:35 +0200
>>
>> I am just reflecting over how I feel every time I peek
>> into souces. It feels like I am looking into sqlite ammalgamation :-).
>
> It was worse just a year ago. It will be better a year from now.
> patches are welcome.
Are there any guidelines if one would like to restructure something?
For example, I am looking a lot in image.c I was playing with line drawing
on an image the other day, and I would love to not have to look into ns
and gdi code while working with x11 & cairo only. It is so easy to miss
if a single line is actually outside of some platform ifdef and similar. It
is so messy, at least if one is n00b like me :-).
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 16:28 ` Pip Cet
@ 2020-05-17 17:00 ` Eli Zaretskii
2020-05-17 18:50 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 17:00 UTC (permalink / raw)
To: Pip Cet; +Cc: emacs-devel, julius.pfrommer
> From: Pip Cet <pipcet@gmail.com>
> Date: Sun, 17 May 2020 16:28:30 +0000
> Cc: Julius Pfrommer <julius.pfrommer@web.de>, emacs-devel@gnu.org
>
> On Sun, May 17, 2020 at 3:56 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > > Date: Sun, 17 May 2020 16:59:53 +0200
> > > From: Julius Pfrommer <julius.pfrommer@web.de>
> > > Cc: emacs-devel@gnu.org
> > Next, please be aware that we already made the decision to use
> > HarfBuzz as our main text-shaping engine.
>
> That's a decision that, having just played with HarfBuzz, I find
> puzzling. It appears to have no practical support for treating
> ligatures as anything but monolithic glyphs: is there a documented way
> of getting HarfBuzz to tell you which part of the "ffi" ligature is
> the middle "f"?
You are accusing HarfBuzz of crimes it didn't commit ;-) What you see
is not produced by HarfBuzz, it's produced by Emacs.
HarfBuzz (and any other text-shaping engine we ever used) has a very
simple job: Emacs hands it a string of codepoints, and HarfBuzz
returns a series of font glyphs to be used to display that string.
That's all. All the rest is the Emacs display engine.
And yes, the current design is that a ligature (like any other
"grapheme cluster" produced by character composition) is a single
"display element": you move across all of it with a single C-f/C-b.
The only exception to this rule is that we allow DEL (but not C-d or
Delete) to erase individual codepoints going back from the end of the
grapheme cluster -- to facilitate editing ligatures and other composed
characters. This is the minimum "editing" capability that the user
must have, and I don't think I've heard complaints that it wasn't
enough. But if required, we could easily add special forward and
backward movements that could "enter" the composed character, we just
need to figure out how to display the result in order to give the user
some visual feedback. (Without visual feedback, I think you can have
it today if you customize global-disable-point-adjustment to a non-nil
value.)
In any case, the question "which part of the ligature corresponds to
some codepoint" is meaningless in the context of ligation and complex
text shaping: a sequence of N codepoints in general produces M font
glyphs, where M can be smaller, equal, or greater than N. The
relation between the N codepoints and M glyphs is many-to-many.
> I'm not sure PangoCairo does better, but whatever Libreoffice uses
> appears to get the job done
What job is that?
> (This is assuming we want kerning, ligatures, and subpixel rendering
> for English text. "Real" text shaping, composition, reordrant glyphs,
> and bidi concerns are something that I can't really comment on, beyond
> admitting that, of course, supporting the world's major languages at
> all is more important than supporting English with the typographic
> finesse we currently lack).
The truth is that "we" the Emacs project don't want to know anything
about ligatures, we want to delegate that job to the shaper. That's
the shaper's job, and HarfBuzz does its job very well and stays on top
of the relevant technological advances.
> Years ago, I ran a WebAssembly version of Emacs in a web browser.
> (Back then, I used a terminal emulator written in JavaScript.) I'd
> certainly like to do that again some day, and I think a hard
> dependency on Cairo and FreeType would make that even harder.
I think there's some measure of confusion here: AFAIR we don't use
Cairo for text shaping, only for its display. IOW, we tell Cairo to
display this and that glyphs, after HarfBuzz returned them.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 16:50 ` Arthur Miller
@ 2020-05-17 17:06 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 17:06 UTC (permalink / raw)
To: Arthur Miller; +Cc: julius.pfrommer, emacs-devel
> From: Arthur Miller <arthur.miller@live.com>
> Cc: emacs-devel@gnu.org, julius.pfrommer@web.de
> Date: Sun, 17 May 2020 18:50:04 +0200
>
> Are there any guidelines if one would like to restructure something?
The guideline is to factor any GUI code into common part and
platform-specific part, and define interfaces for the latter whose
implementation is in the corresponding *term.[cm] or *fns.[cm].
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 15:55 ` Eli Zaretskii
2020-05-17 16:28 ` Pip Cet
@ 2020-05-17 18:28 ` Julius Pfrommer
2020-05-17 18:45 ` Eli Zaretskii
` (2 more replies)
1 sibling, 3 replies; 145+ messages in thread
From: Julius Pfrommer @ 2020-05-17 18:28 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
> First, we need to establish that this is a solution, and for what
> problem(s). It is important to realize that the GUI backends we use
> handle much more than just drawing text, they need to be able to
> display GUI widgets, frame and window decorations (menu bar, tool bar,
> scroll bars, the frame title, etc.), and much more.
I am quite supportive of the native GUI toolkits.
Cairo is a vector-drawing library and only responsible for the "glass"
of each frame (called the "canvas" in other communities). All the
event-handling logic, menu-drawing, etc. is untouched by it.
> Next, please be aware that we already made the decision to use
> HarfBuzz as our main text-shaping engine. X and w32 already use it;
Very good to see Emacs settle on HarfBuzz! Text-shaping touches into the
very core, as the glyph rendering impacts line-breaking, redisplay, and
so on.
> I don't think the answer will be full and definitive until "Someone"
> walks through all the APIs we implement in x/w32/ns/fns.c and
> x/w32/ns/term.c, and makes sure they all can be covered.
Looking at xterm.c, it is littered with #ifdef USE_CAIRO.
A first step could be to assume Cairo on X-based platforms and remove
duplicate code. The second step could be to decouple the "glass" from
the tookit "chrome" more thoroughly in xterm.c. That is easier to do
when a Cairo-canvas can be assumed for drawing.
Then, that entire "glass" could be reused by other platforms once they
have a Cairo-canvas for drawing as well. (Modulo the XWidget support
that depends on GTK.)
Once a switchover is in reach, it can live separately to the existing
platform-specific "glass" until all the kinks are worked out.
Regards, Julius
Am Sun, 17 May 2020 18:55:23 +0300
schrieb Eli Zaretskii <eliz@gnu.org>:
> > Date: Sun, 17 May 2020 16:59:53 +0200
> > From: Julius Pfrommer <julius.pfrommer@web.de>
> > Cc: emacs-devel@gnu.org
> >
> > Let me phrase the question differently: Would it be okay to have a
> > hard dependency on the Cairo+FreeType+Harfbuzz (CFH) libraries, as
> > they are available everywhere?
>
> First, we need to establish that this is a solution, and for what
> problem(s). It is important to realize that the GUI backends we use
> handle much more than just drawing text, they need to be able to
> display GUI widgets, frame and window decorations (menu bar, tool bar,
> scroll bars, the frame title, etc.), and much more. Is the
> configuration you propose capable of doing all that? I don't think
> the answer will be full and definitive until "Someone" walks through
> all the APIs we implement in x/w32/ns/fns.c and x/w32/ns/term.c, and
> makes sure they all can be covered.
>
> Next, please be aware that we already made the decision to use
> HarfBuzz as our main text-shaping engine. X and w32 already use it;
> for NS someone has to write the code (and they are not very likely to
> do so because macOS users consider the native text shaping more
> feature-rich). Dropping the other font backends is a matter of time,
> but it could take a long time.
>
> In any case, the font backend is not the main issue here; in
> particular, the likes of FreeType are hardly even seen except on very
> low level of the code. It's the other aspects of GUI code that
> bothers me much more.
>
> > Even on Linux, this would unlock quite a few simplifications. I
> > count at least three font handling "backends" here.
>
> Down to 2 and one deprecated one on master. Bu again, font backends
> is a relatively easy problem, and it is being dealt with.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 18:28 ` Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
@ 2020-05-17 18:45 ` Eli Zaretskii
2020-05-17 22:28 ` chad
2020-05-18 22:08 ` Alan Third
2 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 18:45 UTC (permalink / raw)
To: Julius Pfrommer; +Cc: emacs-devel
> Date: Sun, 17 May 2020 20:28:02 +0200
> From: Julius Pfrommer <julius.pfrommer@web.de>
> Cc: emacs-devel@gnu.org
>
> Cairo is a vector-drawing library and only responsible for the "glass"
> of each frame (called the "canvas" in other communities). All the
> event-handling logic, menu-drawing, etc. is untouched by it.
Which is what I said. So Cairo alone will be unable to provide all
the GUI features we need, we will need something else. And that
something is done different on different platforms.
> Looking at xterm.c, it is littered with #ifdef USE_CAIRO.
Yes, because Cairo and Xlib are two quite different ways of doing GUI
display.
> A first step could be to assume Cairo on X-based platforms and remove
> duplicate code.
We are going there, but it takes time. We've just made Cairo the
default build on master; it couldn't be that previously because the
Cairo code had several grave bugs which took us time to fix.
> The second step could be to decouple the "glass" from
> the tookit "chrome" more thoroughly in xterm.c. That is easier to do
> when a Cairo-canvas can be assumed for drawing.
>
> Then, that entire "glass" could be reused by other platforms once they
> have a Cairo-canvas for drawing as well. (Modulo the XWidget support
> that depends on GTK.)
>
> Once a switchover is in reach, it can live separately to the existing
> platform-specific "glass" until all the kinks are worked out.
Sounds like a good plan for several years, maybe more, of extensive
development on several platforms. Can I interest you in doing this?
And meanwhile, we also need to come up with enough new features every
2 - 3 years to keep our users engaged and attract new ones.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 17:00 ` Eli Zaretskii
@ 2020-05-17 18:50 ` Pip Cet
2020-05-17 19:17 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-17 18:50 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel, julius.pfrommer
On Sun, May 17, 2020 at 5:00 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sun, 17 May 2020 16:28:30 +0000
> > Cc: Julius Pfrommer <julius.pfrommer@web.de>, emacs-devel@gnu.org
> >
> > On Sun, May 17, 2020 at 3:56 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > > > Date: Sun, 17 May 2020 16:59:53 +0200
> > > > From: Julius Pfrommer <julius.pfrommer@web.de>
> > > > Cc: emacs-devel@gnu.org
> > > Next, please be aware that we already made the decision to use
> > > HarfBuzz as our main text-shaping engine.
> >
> > That's a decision that, having just played with HarfBuzz, I find
> > puzzling. It appears to have no practical support for treating
> > ligatures as anything but monolithic glyphs: is there a documented way
> > of getting HarfBuzz to tell you which part of the "ffi" ligature is
> > the middle "f"?
>
> You are accusing HarfBuzz of crimes it didn't commit ;-) What you see
> is not produced by HarfBuzz, it's produced by Emacs.
I don't think that's true.
> HarfBuzz (and any other text-shaping engine we ever used) has a very
> simple job: Emacs hands it a string of codepoints, and HarfBuzz
> returns a series of font glyphs to be used to display that string.
> That's all. All the rest is the Emacs display engine.
HarfBuzz also tells you which codepoints are used for which glyphs. It
should also, for languages where it can do so, tell you which
codepoints are used for which subglyphs. It fails to do the latter.
(I'm aware of what the Emacs display engine does; I'm, obviously, not
accusing HarfBuzz of failing to present ligatures, because that's
easily fixable. What isn't easily fixable is going back from the
ligature glyph to its subglyphs. LibreOffice does it, and I wonder
how, because the alternative is jumping back and forth between
ligatures and individual characters depending on where PT is, and that
looks horrible.)
> And yes, the current design is that a ligature (like any other
> "grapheme cluster" produced by character composition) is a single
> "display element": you move across all of it with a single C-f/C-b.
I'm using a different design :-)
That one is simply unworkable for English and its limited traditional
set of ligatures.
> In any case, the question "which part of the ligature corresponds to
> some codepoint" is meaningless in the context of ligation and complex
> text shaping:
No, it's not. It's meaningless for some languages, but not for English
and its limited set of traditional ligatures. That a problem cannot be
solved in general is no excuse to refuse to solve it in the specific
cases where it can be.
> > I'm not sure PangoCairo does better, but whatever Libreoffice uses
> > appears to get the job done
>
> What job is that?
LibreOffice highlights sub-glyphs of ligatures correctly. I enter
"official", and it renders <o> <ffi> <c> <i> <a> <l>. I move the
cursor right twice, and it highlights precisely what it should, the
middle "f" of the ligature glyph.
> > (This is assuming we want kerning, ligatures, and subpixel rendering
> > for English text. "Real" text shaping, composition, reordrant glyphs,
> > and bidi concerns are something that I can't really comment on, beyond
> > admitting that, of course, supporting the world's major languages at
> > all is more important than supporting English with the typographic
> > finesse we currently lack).
>
> The truth is that "we" the Emacs project don't want to know anything
> about ligatures, we want to delegate that job to the shaper.
I don't see how that's true. Treating a ligature as a single character
for entry purposes is simply unworkable for English. It might be okay
for other languages, but for English, we really need to display "ffi"
correctly and still allow it to be edited as three characters.
> That's
> the shaper's job, and HarfBuzz does its job very well and stays on top
> of the relevant technological advances.
I don't see any evidence for that positive statement about HarfBuzz:
out of the box, Emacs fails miserably to do anything about English
ligatures. Trying to find a way to fix it, I ran into HarfBuzz
limitations that appear to make it impossible to use it to deal with
English ligatures. It might deal very well with other languages and
their ligatures, but for English text, it fails to do what TeX did
since its inception.
> > Years ago, I ran a WebAssembly version of Emacs in a web browser.
> > (Back then, I used a terminal emulator written in JavaScript.) I'd
> > certainly like to do that again some day, and I think a hard
> > dependency on Cairo and FreeType would make that even harder.
>
> I think there's some measure of confusion here: AFAIR we don't use
> Cairo for text shaping, only for its display. IOW, we tell Cairo to
> display this and that glyphs, after HarfBuzz returned them.
Yes, that's correct. Which means that a WebAssembly version of Emacs
would need to bundle Cairo, even though it would prefer to simply
render things in the browser using HTML 5 canvases or something
similar.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 18:50 ` Pip Cet
@ 2020-05-17 19:17 ` Eli Zaretskii
2020-05-18 16:08 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-17 19:17 UTC (permalink / raw)
To: Pip Cet; +Cc: emacs-devel, julius.pfrommer
> From: Pip Cet <pipcet@gmail.com>
> Date: Sun, 17 May 2020 18:50:19 +0000
> Cc: julius.pfrommer@web.de, emacs-devel@gnu.org
>
> HarfBuzz also tells you which codepoints are used for which glyphs. It
> should also, for languages where it can do so, tell you which
> codepoints are used for which subglyphs. It fails to do the latter.
No, it doesn't fail. You can see what it tells us in the display of
the composition produced by "C-u C-x =".
> That one is simply unworkable for English and its limited traditional
> set of ligatures.
The main reason we want ligatures in Emacs is for displaying program
source. Latin ligatures are not the main reason. But I see no reason
we couldn't do what you want, it's just the question of someone who'd
need to write the code. The information is there.
> LibreOffice highlights sub-glyphs of ligatures correctly. I enter
> "official", and it renders <o> <ffi> <c> <i> <a> <l>. I move the
> cursor right twice, and it highlights precisely what it should, the
> middle "f" of the ligature glyph.
We can do that in Emacs as well. The information is there, we just
need to use it. For Latin ligatures that information will allow the
display you describe. Doing that for other scripts would be harder,
and the results will be less one-to-one.
> > The truth is that "we" the Emacs project don't want to know anything
> > about ligatures, we want to delegate that job to the shaper.
>
> I don't see how that's true. Treating a ligature as a single character
> for entry purposes is simply unworkable for English.
I didn't say we must treat ligatures as a single character, I just
said we do that now. But that has nothing to do with the fact that we
want all the information about the ligature to come from the shaper.
> out of the box, Emacs fails miserably to do anything about English
> ligatures. Trying to find a way to fix it, I ran into HarfBuzz
> limitations that appear to make it impossible to use it to deal with
> English ligatures. It might deal very well with other languages and
> their ligatures, but for English text, it fails to do what TeX did
> since its inception.
I don't think this is right, but since you haven't shown any code, or
what you tried to do, or which HarfBuzz limitations you allude to, it
is hard to be more specific. I can only suggest, again, to look at
the output of "C-u C-x =" -- that information comes directly from
HarfBuzz.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 18:28 ` Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
2020-05-17 18:45 ` Eli Zaretskii
@ 2020-05-17 22:28 ` chad
2020-05-18 22:08 ` Alan Third
2 siblings, 0 replies; 145+ messages in thread
From: chad @ 2020-05-17 22:28 UTC (permalink / raw)
To: Julius Pfrommer; +Cc: Eli Zaretskii, EMACS development team
[-- Attachment #1: Type: text/plain, Size: 727 bytes --]
On Sun, May 17, 2020 at 11:30 AM Julius Pfrommer <julius.pfrommer@web.de>
wrote:
> A first step could be to assume Cairo on X-based platforms and remove
> duplicate code. The second step could be to decouple the "glass" from
> the tookit "chrome" more thoroughly in xterm.c. That is easier to do
> when a Cairo-canvas can be assumed for drawing.
>
> Then, that entire "glass" could be reused by other platforms once they
> have a Cairo-canvas for drawing as well. (Modulo the XWidget support
> that depends on GTK.)
>
FWIW, there exists code to bring xwidgets and webkit into macOS without GTK:
https://github.com/veshboo/emacs
I haven't tried it since my macOS machine died ~1.5 years ago, but it
worked once upon a time.
[-- Attachment #2: Type: text/html, Size: 1210 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-17 19:17 ` Eli Zaretskii
@ 2020-05-18 16:08 ` Eli Zaretskii
2020-05-18 16:45 ` tomas
` (3 more replies)
0 siblings, 4 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 16:08 UTC (permalink / raw)
To: pipcet; +Cc: emacs-devel
> Date: Sun, 17 May 2020 22:17:17 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: emacs-devel@gnu.org, julius.pfrommer@web.de
>
> > LibreOffice highlights sub-glyphs of ligatures correctly. I enter
> > "official", and it renders <o> <ffi> <c> <i> <a> <l>. I move the
> > cursor right twice, and it highlights precisely what it should, the
> > middle "f" of the ligature glyph.
>
> We can do that in Emacs as well. The information is there, we just
> need to use it. For Latin ligatures that information will allow the
> display you describe. Doing that for other scripts would be harder,
> and the results will be less one-to-one.
On second thought, I think I misunderstood you. If the font that is
used shows "ffi" as a _single_ glyph ffi, and LibreOffice indeed
highlights parts of this glyph, then I'd like to know how it does
that, and how far does this capability extend. I mean, what does it
do with ligatures like ae, displayed as æ -- does it highlight the
common vertical stroke for both parts? And what about "st", displayed
as st -- this has a curved "hand" connecting s and t -- to which of the
2 does it belong for the purposes of highlighting? There's also "hv"
displayed as ƕ, let alone "fs" displayed as ẞ and "fz" displayed as
ß.
IOW, I really don't think I understand how this could work even for
what you call "English ligatures". Do you know how they do it?
The information I said we get from HarfBuzz is returned when HarfBuzz
produces a grapheme cluster from several font glyphs. When the result
is a single font glyph, that information just says which of the
original codepoints are to be displayed as that single glyph, it
doesn't provide any sub-glyph information.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 16:08 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
@ 2020-05-18 16:45 ` tomas
2020-05-18 16:49 ` Eli Zaretskii
2020-05-18 17:05 ` Ligatures Stefan Monnier
` (2 subsequent siblings)
3 siblings, 1 reply; 145+ messages in thread
From: tomas @ 2020-05-18 16:45 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: pipcet, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 866 bytes --]
On Mon, May 18, 2020 at 07:08:45PM +0300, Eli Zaretskii wrote:
> > Date: Sun, 17 May 2020 22:17:17 +0300
> > From: Eli Zaretskii <eliz@gnu.org>
> > Cc: emacs-devel@gnu.org, julius.pfrommer@web.de
> >
> > > LibreOffice highlights sub-glyphs of ligatures correctly. I enter
> > > "official", and it renders <o> <ffi> <c> <i> <a> <l>. I move the
> > > cursor right twice, and it highlights precisely what it should, the
> > > middle "f" of the ligature glyph.
[...]
> On second thought, I think I misunderstood you. If the font that is
> used shows "ffi" as a _single_ glyph ffi, and LibreOffice indeed
> highlights parts of this glyph, then I'd like to know how it does
> that [...]
Didn't work for me [1]. It treated the whole ligature as one "character".
Cheers
[1] LibreOffice 6.1.5.2 10(Build:2), Debian GNU/Linux (buster).
-- tomás
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 16:45 ` tomas
@ 2020-05-18 16:49 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 16:49 UTC (permalink / raw)
To: tomas; +Cc: pipcet, emacs-devel
> Date: Mon, 18 May 2020 18:45:43 +0200
> Cc: pipcet@gmail.com, emacs-devel@gnu.org
> From: <tomas@tuxteam.de>
>
> > On second thought, I think I misunderstood you. If the font that is
> > used shows "ffi" as a _single_ glyph ffi, and LibreOffice indeed
> > highlights parts of this glyph, then I'd like to know how it does
> > that [...]
>
> Didn't work for me [1]. It treated the whole ligature as one "character".
That's what I'd expect.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 16:08 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
2020-05-18 16:45 ` tomas
@ 2020-05-18 17:05 ` Stefan Monnier
2020-05-18 17:18 ` Ligatures Eli Zaretskii
2020-05-18 17:24 ` Ligatures tomas
2020-05-18 17:31 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Clément Pit-Claudel
2020-05-19 5:43 ` Ligatures ASSI
3 siblings, 2 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-18 17:05 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: pipcet, emacs-devel
[ I know nothing about the underlying APIs and such, so speaking here
only as a random user. ]
> On second thought, I think I misunderstood you. If the font that is
> used shows "ffi" as a _single_ glyph ffi, and LibreOffice indeed
> highlights parts of this glyph, then I'd like to know how it does
> that, and how far does this capability extend. I mean, what does it
> do with ligatures like ae, displayed as æ -- does it highlight the
> common vertical stroke for both parts? And what about "st", displayed
> as st -- this has a curved "hand" connecting s and t -- to which of the
> 2 does it belong for the purposes of highlighting?
As a mere user I wouldn't care very much about this detail: I'd just
want the cursor to have 2 different positions depending on whether I'm
on the "s" or on the "t", and hopefully those two positions are
sufficiently self-evident that I don't have to read a manual to
understand which is which.
So, maybe we don't need very much info: all we need is a boolean which
tells us whether the glyph should be treated atomically or not.
When not treating it atomically, we would (somewhat arbitrarily) divide
the glyph horizontally into N equal sized "subglyphs" and draw the
cursor on the corresponding subglyph.
If Harfbuzz could tell us more precisely how to divide the glyph into
subglyphs, we could do a better job, of course.
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 17:05 ` Ligatures Stefan Monnier
@ 2020-05-18 17:18 ` Eli Zaretskii
2020-05-18 19:19 ` Ligatures Pip Cet
2020-05-18 17:24 ` Ligatures tomas
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 17:18 UTC (permalink / raw)
To: Stefan Monnier; +Cc: pipcet, emacs-devel
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: pipcet@gmail.com, emacs-devel@gnu.org
> Date: Mon, 18 May 2020 13:05:53 -0400
>
> So, maybe we don't need very much info: all we need is a boolean which
> tells us whether the glyph should be treated atomically or not.
> When not treating it atomically, we would (somewhat arbitrarily) divide
> the glyph horizontally into N equal sized "subglyphs" and draw the
> cursor on the corresponding subglyph.
That strikes me as not a very user-friendly UX. Especially if you
keep in mind that glyphs can be composed into a grapheme cluster using
2D offsets, not just left-right one-dimensional offsets.
An alternative which might be nicer is to "split" the composition:
display it as if a ZWNJ character was inserted at point. Thus, moving
forward one buffer position into the ffi would show f followed by a thin bar
cursor followed by the fi; moving forward one more buffer position
would show ff followed by a thin bar cursor followed by i. Etc.
> If Harfbuzz could tell us more precisely how to divide the glyph into
> subglyphs, we could do a better job, of course.
I don't think it's possible because AFAIK fonts don't store this
information. It should be possible, of course, to have a private
database of such offsets, but I don't really see how it could work in
general.
Maybe I'm missing something, though. If someone wants to have a
definitive answer, I suggest to ask on the HarfBuzz mailing list.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 17:05 ` Ligatures Stefan Monnier
2020-05-18 17:18 ` Ligatures Eli Zaretskii
@ 2020-05-18 17:24 ` tomas
2020-05-18 17:41 ` Ligatures Eli Zaretskii
2020-05-18 20:33 ` Ligatures Stefan Monnier
1 sibling, 2 replies; 145+ messages in thread
From: tomas @ 2020-05-18 17:24 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 909 bytes --]
On Mon, May 18, 2020 at 01:05:53PM -0400, Stefan Monnier wrote:
> [ I know nothing about the underlying APIs and such, so speaking here
> only as a random user. ]
[...]
> So, maybe we don't need very much info: all we need is a boolean which
> tells us whether the glyph should be treated atomically or not.
> When not treating it atomically, we would (somewhat arbitrarily) divide
> the glyph horizontally into N equal sized "subglyphs" and draw the
> cursor on the corresponding subglyph.
I'm somewhat out of my depth here, but I have the hunch that some
"ligatures" aren't "just stacked horizontally".
> If Harfbuzz could tell us more precisely how to divide the glyph into
> subglyphs, we could do a better job, of course.
On a very superficial glance it seems they can [1]
Cheers
[1] https://github.com/harfbuzz/harfbuzz/blob/master/docs/usermanual-clusters.xml
-- tomás
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 16:08 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
2020-05-18 16:45 ` tomas
2020-05-18 17:05 ` Ligatures Stefan Monnier
@ 2020-05-18 17:31 ` Clément Pit-Claudel
2020-05-18 17:39 ` Eli Zaretskii
2020-05-19 10:09 ` Trevor Spiteri
2020-05-19 5:43 ` Ligatures ASSI
3 siblings, 2 replies; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-18 17:31 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1024 bytes --]
On 18/05/2020 12.08, Eli Zaretskii wrote:
> On second thought, I think I misunderstood you. If the font that is
> used shows "ffi" as a _single_ glyph ffi, and LibreOffice indeed
> highlights parts of this glyph, then I'd like to know how it does
> that, and how far does this capability extend. I mean, what does it
> do with ligatures like ae, displayed as æ -- does it highlight the
> common vertical stroke for both parts? And what about "st", displayed
> as st -- this has a curved "hand" connecting s and t -- to which of the
> 2 does it belong for the purposes of highlighting? There's also "hv"
> displayed as ƕ, let alone "fs" displayed as ẞ and "fz" displayed as
> ß.
I've attached a screenshot with a few examples, though I couldn't find a font that displays ae as æ.
Firefox does the same as LibreOffice (try it here, for example: https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant-ligatures). Since Firefox uses Harbuzz, I think there's a good chance we can support that feature too :)
[-- Attachment #2: ligatures.png --]
[-- Type: image/png, Size: 13362 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 17:31 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Clément Pit-Claudel
@ 2020-05-18 17:39 ` Eli Zaretskii
2020-05-18 19:01 ` Clément Pit-Claudel
2020-05-19 10:09 ` Trevor Spiteri
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 17:39 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Mon, 18 May 2020 13:31:30 -0400
>
> I've attached a screenshot with a few examples, though I couldn't find a font that displays ae as æ.
Thanks. Once again, I wonder how they decide where each parts starts
and ends. The examples show very simple cases, so it's hard to know
where this ends.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 17:24 ` Ligatures tomas
@ 2020-05-18 17:41 ` Eli Zaretskii
2020-05-18 19:07 ` Ligatures tomas
2020-05-18 20:33 ` Ligatures Stefan Monnier
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 17:41 UTC (permalink / raw)
To: tomas; +Cc: emacs-devel
> Date: Mon, 18 May 2020 19:24:41 +0200
> From: <tomas@tuxteam.de>
>
> > If Harfbuzz could tell us more precisely how to divide the glyph into
> > subglyphs, we could do a better job, of course.
>
> On a very superficial glance it seems they can [1]
>
> Cheers
> [1] https://github.com/harfbuzz/harfbuzz/blob/master/docs/usermanual-clusters.xml
AFAIK, each "cluster" corresponds to a single font glyph, and we
already get this information from HarfBuzz, see hbfont.c.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 17:39 ` Eli Zaretskii
@ 2020-05-18 19:01 ` Clément Pit-Claudel
2020-05-18 19:15 ` Eli Zaretskii
` (3 more replies)
0 siblings, 4 replies; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-18 19:01 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
On 18/05/2020 13.39, Eli Zaretskii wrote:
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Mon, 18 May 2020 13:31:30 -0400
>>
>> I've attached a screenshot with a few examples, though I couldn't find a font that displays ae as æ.
>
> Thanks. Once again, I wonder how they decide where each parts starts
> and ends. The examples show very simple cases, so it's hard to know
> where this ends.
Hi Eli,
I asked on Firefox' Matrix server. Here is a lightly edited transcript:
cpitclaudel> Hi all. I noticed that Firefox has this nifty feature that makes it possible to move the cursor within a ligature (for example, with the right font config, "ffi" can be rendered as "ffi" while allowing the cursor to move between the individual glyphs that make up that composition). Is the extraction of ligature information and the rendering done by Firefox itself, or by a lower-level library? Most font shaping libraries I've seen don't seem to return glyph-decomposition information for ligatures, so I'm curious to understand how Firefox does it ^^
jfkthame> Firefox uses harfbuzz to handle the font shaping (ligature rules, etc). I'd expect what you describe to work pretty much the same in other browsers too, fwiw.
krosylight
cpitclaudel> Thanks! But Harfbuzz doesn't give sub-glyph information for ligatures, does it? So how does Firefox know where to put the caret when it moves through a ligature?
jfkthame> it doesn't, really - it just knows how many underlying characters are represented by the ligature glyph, and divides the advance width up into that many slices (usually that works pretty reasonably, but it's possible to come up with fonts where the inaccuracy becomes obvious)
jfkthame> In principle, OpenType fonts can provide specific positions for the caret within a ligature (see the LigatureCaretList subtable within the GDEF table), but in practice that's rarely supported or used (harfbuzz can provide this information if it's present, see the hb_ot_layout_get_ligature_carets function, but currently firefox doesn't use it anyhow)
cpitclaudel> Thanks, that's very useful! How does that work for glyphs like "fs" displayed as ẞ or "fz" displayed as ß? Does Firefox move in that single glyph? (I couldn't find a font that does that, otherwise I'd have tested it ^^) Thanks a lot for your help :)
jfkthame> Yes, it'd be the same - doesn't matter what the specific characters are, if there's a ligature of two characters Firefox would put the caret half-way through the ligature glyph when it is between the component characters in the underlying text
jfkthame> btw, if you're on a mac (or have access to one), you can see an extreme case if you try the word "Zapfino" in the font Zapfino .... the entire word is a single 7-character ligature, and the seven equal slices that Firefox treats it as for selection/editing purposes don't match up to the visual shapes of the sub-glyphs at all well
HTH,
Clément.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 17:41 ` Ligatures Eli Zaretskii
@ 2020-05-18 19:07 ` tomas
2020-05-18 19:17 ` Ligatures Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: tomas @ 2020-05-18 19:07 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 744 bytes --]
On Mon, May 18, 2020 at 08:41:09PM +0300, Eli Zaretskii wrote:
> > Date: Mon, 18 May 2020 19:24:41 +0200
> > From: <tomas@tuxteam.de>
> >
> > > If Harfbuzz could tell us more precisely how to divide the glyph into
> > > subglyphs, we could do a better job, of course.
> >
> > On a very superficial glance it seems they can [1]
> >
> > Cheers
> > [1] https://github.com/harfbuzz/harfbuzz/blob/master/docs/usermanual-clusters.xml
>
> AFAIK, each "cluster" corresponds to a single font glyph, and we
> already get this information from HarfBuzz, see hbfont.c.
I see, thanks. As I said, my reading was a very cursory. I'm sure
you read that doc much more thoroughly than me :-)
Thanks for the insights
Cheers
-- tomás
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 19:01 ` Clément Pit-Claudel
@ 2020-05-18 19:15 ` Eli Zaretskii
2020-05-18 19:18 ` tomas
` (2 subsequent siblings)
3 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 19:15 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
> Cc: emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Mon, 18 May 2020 15:01:49 -0400
>
> I asked on Firefox' Matrix server. Here is a lightly edited transcript:
Thanks. So it's pure heuristic, and works only in simple cases.
We could ask on the HarfBuzz list how many fonts provide meaningful
information for the hb_ot_layout_get_ligature_carets function to
return useful data. If someone is interested in working on that, that
is.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:07 ` Ligatures tomas
@ 2020-05-18 19:17 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 19:17 UTC (permalink / raw)
To: tomas; +Cc: emacs-devel
> Date: Mon, 18 May 2020 21:07:35 +0200
> From: tomas@tuxteam.de
> Cc: emacs-devel@gnu.org
>
> > > [1] https://github.com/harfbuzz/harfbuzz/blob/master/docs/usermanual-clusters.xml
> >
> > AFAIK, each "cluster" corresponds to a single font glyph, and we
> > already get this information from HarfBuzz, see hbfont.c.
>
> I see, thanks. As I said, my reading was a very cursory. I'm sure
> you read that doc much more thoroughly than me :-)
Some of the docs is impossible to understand without asking the
HarfBuzz developers (who are always willing to help). The HarfBuzz
docs is really minimal.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 19:01 ` Clément Pit-Claudel
2020-05-18 19:15 ` Eli Zaretskii
@ 2020-05-18 19:18 ` tomas
2020-05-18 20:37 ` Ligatures Stefan Monnier
2020-05-18 21:59 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Alan Third
3 siblings, 0 replies; 145+ messages in thread
From: tomas @ 2020-05-18 19:18 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 968 bytes --]
On Mon, May 18, 2020 at 03:01:49PM -0400, Clément Pit-Claudel wrote:
> On 18/05/2020 13.39, Eli Zaretskii wrote:
> >> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> >> Date: Mon, 18 May 2020 13:31:30 -0400
> >>
> >> I've attached a screenshot with a few examples, though I couldn't find a font that displays ae as æ.
> >
> > Thanks. Once again, I wonder how they decide where each parts starts
> > and ends. The examples show very simple cases, so it's hard to know
> > where this ends.
>
> Hi Eli,
>
> I asked on Firefox' Matrix server. Here is a lightly edited transcript:
Thanks, that's interesting. So they just assume the subcharacters in a
cluster stack side-by-side. Works most of the time, but is bound to
give surprising results with things which stack the "wrong" way (i.e.
on the top or bottom for LR or RL scripts, like accents and crazy
scripts like Devanagari).
Thanks for gathering the information.
Cheers
-- t
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 17:18 ` Ligatures Eli Zaretskii
@ 2020-05-18 19:19 ` Pip Cet
2020-05-18 19:25 ` Ligatures tomas
` (2 more replies)
0 siblings, 3 replies; 145+ messages in thread
From: Pip Cet @ 2020-05-18 19:19 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Stefan Monnier, emacs-devel
On Mon, May 18, 2020 at 5:18 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > So, maybe we don't need very much info: all we need is a boolean which
> > tells us whether the glyph should be treated atomically or not.
> > When not treating it atomically, we would (somewhat arbitrarily) divide
> > the glyph horizontally into N equal sized "subglyphs" and draw the
> > cursor on the corresponding subglyph.
>
> That strikes me as not a very user-friendly UX. Especially if you
> keep in mind that glyphs can be composed into a grapheme cluster using
> 2D offsets, not just left-right one-dimensional offsets.
So such clusters would be marked as atomic? I like Stefan's proposal,
and maybe it's what LibreOffice actually does: at large font sizes,
the horizontal division of "subglyphs" seems off.
> An alternative which might be nicer is to "split" the composition:
> display it as if a ZWNJ character was inserted at point. Thus, moving
> forward one buffer position into the ffi would show f followed by a thin bar
> cursor followed by the fi; moving forward one more buffer position
> would show ff followed by a thin bar cursor followed by i. Etc.
I tried something like that (with a variable-pitch font), and the
effect is nauseating because the rest of the line shifts as the width
of the word at point changes. What I tried was to use Harfbuzz to
shape entire words when PT is not in them, then split them up into
individual characters (the way it's done now) when PT enters them.
Of course, people might still like it.
> > If Harfbuzz could tell us more precisely how to divide the glyph into
> > subglyphs, we could do a better job, of course.
>
> I don't think it's possible because AFAIK fonts don't store this
> information.
Well, they should!
> It should be possible, of course, to have a private
> database of such offsets, but I don't really see how it could work in
> general.
And this is where it gets back to "let's not hardcode the dependency
on Harfbuzz and FreeType, because other backends might actually give
us the information we need".
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:19 ` Ligatures Pip Cet
@ 2020-05-18 19:25 ` tomas
2020-05-18 19:41 ` Ligatures Pip Cet
2020-05-18 19:33 ` Ligatures Eli Zaretskii
2020-05-18 19:38 ` Ligatures Clément Pit-Claudel
2 siblings, 1 reply; 145+ messages in thread
From: tomas @ 2020-05-18 19:25 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 406 bytes --]
On Mon, May 18, 2020 at 07:19:19PM +0000, Pip Cet wrote:
[...]
> And this is where it gets back to "let's not hardcode the dependency
> on Harfbuzz and FreeType, because other backends might actually give
> us the information we need".
But how should a backend guess where the subparts of a cluster are
without the font providing it? And in the latter case, HarfBuzz
does give us the info.
Cheers
-- t
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:19 ` Ligatures Pip Cet
2020-05-18 19:25 ` Ligatures tomas
@ 2020-05-18 19:33 ` Eli Zaretskii
2020-05-18 19:44 ` Ligatures Clément Pit-Claudel
2020-05-18 19:38 ` Ligatures Clément Pit-Claudel
2 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-18 19:33 UTC (permalink / raw)
To: Pip Cet; +Cc: monnier, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Mon, 18 May 2020 19:19:19 +0000
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, emacs-devel@gnu.org
>
> > An alternative which might be nicer is to "split" the composition:
> > display it as if a ZWNJ character was inserted at point. Thus, moving
> > forward one buffer position into the ffi would show f followed by a thin bar
> > cursor followed by the fi; moving forward one more buffer position
> > would show ff followed by a thin bar cursor followed by i. Etc.
>
> I tried something like that (with a variable-pitch font), and the
> effect is nauseating because the rest of the line shifts as the width
> of the word at point changes.
The idea is that this is used only rarely. Most use cases don't need
to deconstruct a ligature that way; after all, that's what ligatures
are for.
> And this is where it gets back to "let's not hardcode the dependency
> on Harfbuzz and FreeType, because other backends might actually give
> us the information we need".
You cannot avoid hardcoding something, because each shaper has its
idiosyncrasies. But those are only limited to the implementation of
the font driver interfaces described in font.h, they don't leak above
that level. So if we will support such sub-glyph movements, we will
probably introduce one more method into the font driver interface, and
the display engine will use that.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:19 ` Ligatures Pip Cet
2020-05-18 19:25 ` Ligatures tomas
2020-05-18 19:33 ` Ligatures Eli Zaretskii
@ 2020-05-18 19:38 ` Clément Pit-Claudel
2020-05-19 14:55 ` Ligatures Pip Cet
2 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-18 19:38 UTC (permalink / raw)
To: emacs-devel
On 18/05/2020 15.19, Pip Cet wrote:
> So such clusters would be marked as atomic? I like Stefan's proposal,
> and maybe it's what LibreOffice actually does: at large font sizes,
> the horizontal division of "subglyphs" seems off.
Yup, that's what Firefox and LibreOffice do.
>>> If Harfbuzz could tell us more precisely how to divide the glyph into
>>> subglyphs, we could do a better job, of course.
>>
>> I don't think it's possible because AFAIK fonts don't store this
>> information.
>
> Well, they should!
They can, but few do (the LigatureCaretList subtable within the GDEF table)
>> It should be possible, of course, to have a private
>> database of such offsets, but I don't really see how it could work in
>> general.
>
> And this is where it gets back to "let's not hardcode the dependency
> on Harfbuzz and FreeType, because other backends might actually give
> us the information we need".
Harfbuzz can give us this info: hb_ot_layout_get_ligature_carets
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:25 ` Ligatures tomas
@ 2020-05-18 19:41 ` Pip Cet
2020-05-18 20:20 ` Ligatures tomas
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-18 19:41 UTC (permalink / raw)
To: tomas; +Cc: emacs-devel
On Mon, May 18, 2020 at 7:27 PM <tomas@tuxteam.de> wrote:
> > And this is where it gets back to "let's not hardcode the dependency
> > on Harfbuzz and FreeType, because other backends might actually give
> > us the information we need".
>
> But how should a backend guess where the subparts of a cluster are
> without the font providing it?
Well, of course it shouldn't. It should return the information that is
available, and then we can decide, based on a user setting, what we
want to do about it: the options are, at least, to treat the ligature
as atomic (the right thing to do for ligatures like %, &, and ß),
guess (possibly the right thing to do for ffi?), or refuse to use the
ligature in question and fall back to individual characters (which
isn't always possible, but it is what we do right now for ASCII
ligatures).
> And in the latter case, HarfBuzz
> does give us the info.
How so? I honestly don't think it does, because it would treat the
ligature as one glyph.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:33 ` Ligatures Eli Zaretskii
@ 2020-05-18 19:44 ` Clément Pit-Claudel
2020-05-19 2:25 ` Ligatures Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-18 19:44 UTC (permalink / raw)
To: emacs-devel
On 18/05/2020 15.33, Eli Zaretskii wrote:
>> From: Pip Cet <pipcet@gmail.com>
>> Date: Mon, 18 May 2020 19:19:19 +0000
>> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, emacs-devel@gnu.org
>>
>>> An alternative which might be nicer is to "split" the composition:
>>> display it as if a ZWNJ character was inserted at point. Thus, moving
>>> forward one buffer position into the ffi would show f followed by a thin bar
>>> cursor followed by the fi; moving forward one more buffer position
>>> would show ff followed by a thin bar cursor followed by i. Etc.
>> I tried something like that (with a variable-pitch font), and the
>> effect is nauseating because the rest of the line shifts as the width
>> of the word at point changes.
> The idea is that this is used only rarely. Most use cases don't need
> to deconstruct a ligature that way; after all, that's what ligatures
> are for.
In an earlier thread, you mentioned programming font ligatures — wouldn't it be very common to deconstruct such ligatures, like → into ->?
Maybe the effect wouldn't be jarring with monospaced fonts, but for these the simple approach of subdividing the glyph works nicely too.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:41 ` Ligatures Pip Cet
@ 2020-05-18 20:20 ` tomas
0 siblings, 0 replies; 145+ messages in thread
From: tomas @ 2020-05-18 20:20 UTC (permalink / raw)
To: Pip Cet; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 603 bytes --]
On Mon, May 18, 2020 at 07:41:19PM +0000, Pip Cet wrote:
> On Mon, May 18, 2020 at 7:27 PM <tomas@tuxteam.de> wrote:
[...]
> > But how should a backend guess where the subparts of a cluster are
> > without the font providing it?
>
> Well, of course it shouldn't. It should return the information that is
> available [...]
> > And in the latter case, HarfBuzz
> > does give us the info.
>
> How so? I honestly don't think it does, because it would treat the
> ligature as one glyph.
Eli and Clément already looked it up for us: hb_ot_layout_get_ligature_carets()
Cheers
-- t
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 17:24 ` Ligatures tomas
2020-05-18 17:41 ` Ligatures Eli Zaretskii
@ 2020-05-18 20:33 ` Stefan Monnier
1 sibling, 0 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-18 20:33 UTC (permalink / raw)
To: tomas; +Cc: emacs-devel
>> So, maybe we don't need very much info: all we need is a boolean which
>> tells us whether the glyph should be treated atomically or not.
>> When not treating it atomically, we would (somewhat arbitrarily) divide
>> the glyph horizontally into N equal sized "subglyphs" and draw the
>> cursor on the corresponding subglyph.
>
> I'm somewhat out of my depth here, but I have the hunch that some
> "ligatures" aren't "just stacked horizontally".
That's why we need a boolean to tell us whether this ligature is
"stacked horizontally" (which I called "not atomic").
This boolean could actually be a global constant (so it give the wrong
behavior half the time, but that would be good enough for those people
who use the kind of latin-ligatures talked about here and almost no
other ligatures, and would be no-worse than what we have now for people
who do use languages where many ligatures aren't "stacked horizontally".
But rather than a global constant, we could probably try and do better
either by asking the font-backend (in case it can provide that kind of
info) of by using a heuristic based on the script of the characters that
are being combined.
Obviously, I'm discussing a *heuristic*, not a 100% perfect solution.
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:01 ` Clément Pit-Claudel
2020-05-18 19:15 ` Eli Zaretskii
2020-05-18 19:18 ` tomas
@ 2020-05-18 20:37 ` Stefan Monnier
2020-05-18 21:59 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Alan Third
3 siblings, 0 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-18 20:37 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: Eli Zaretskii, emacs-devel
> jfkthame> it doesn't, really - it just knows how many underlying characters
> jfkthame> are represented by the ligature glyph, and divides the advance
> jfkthame> width up into that many slices (usually that works pretty
> jfkthame> reasonably, but it's possible to come up with fonts where the
> jfkthame> inaccuracy becomes obvious)
Apparently, great minds think alike ;-)
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 19:01 ` Clément Pit-Claudel
` (2 preceding siblings ...)
2020-05-18 20:37 ` Ligatures Stefan Monnier
@ 2020-05-18 21:59 ` Alan Third
2020-05-19 13:56 ` Eli Zaretskii
3 siblings, 1 reply; 145+ messages in thread
From: Alan Third @ 2020-05-18 21:59 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: Eli Zaretskii, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 721 bytes --]
On Mon, May 18, 2020 at 03:01:49PM -0400, Clément Pit-Claudel wrote:
> jfkthame> btw, if you're on a mac (or have access to one), you can
> see an extreme case if you try the word "Zapfino" in the font
> Zapfino .... the entire word is a single 7-character ligature, and
> the seven equal slices that Firefox treats it as for
> selection/editing purposes don't match up to the visual shapes of
> the sub-glyphs at all well
In case anyone's interested, I've attached a screenshot of Apple's
Pages.app displaying the word Zapfino with the cursor after the "a".
Clearly not ideal. OTOH, if LibreOffice, Firefox, and even Apple's
products do this, perhaps it's just the way people will expect it to
be done.
--
Alan Third
[-- Attachment #2: Screenshot 2020-05-18 at 22.52.23.png --]
[-- Type: image/png, Size: 28933 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)
2020-05-17 18:28 ` Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
2020-05-17 18:45 ` Eli Zaretskii
2020-05-17 22:28 ` chad
@ 2020-05-18 22:08 ` Alan Third
2 siblings, 0 replies; 145+ messages in thread
From: Alan Third @ 2020-05-18 22:08 UTC (permalink / raw)
To: Julius Pfrommer; +Cc: Eli Zaretskii, emacs-devel
On Sun, May 17, 2020 at 08:28:02PM +0200, Julius Pfrommer wrote:
> > I don't think the answer will be full and definitive until "Someone"
> > walks through all the APIs we implement in x/w32/ns/fns.c and
> > x/w32/ns/term.c, and makes sure they all can be covered.
>
> Looking at xterm.c, it is littered with #ifdef USE_CAIRO.
>
> A first step could be to assume Cairo on X-based platforms and remove
> duplicate code. The second step could be to decouple the "glass" from
> the tookit "chrome" more thoroughly in xterm.c. That is easier to do
> when a Cairo-canvas can be assumed for drawing.
>
> Then, that entire "glass" could be reused by other platforms once they
> have a Cairo-canvas for drawing as well. (Modulo the XWidget support
> that depends on GTK.)
>
> Once a switchover is in reach, it can live separately to the existing
> platform-specific "glass" until all the kinks are worked out.
It may be worth your while looking into the PGTK port that some people
are working on:
https://github.com/masm11/emacs
I believe it will be using pure Cairo rendering which may make this
project a bit easier.
--
Alan Third
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:44 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 2:25 ` Eli Zaretskii
2020-05-19 2:44 ` Ligatures Clément Pit-Claudel
2020-05-19 3:47 ` Ligatures Stefan Monnier
0 siblings, 2 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 2:25 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Mon, 18 May 2020 15:44:01 -0400
>
> > The idea is that this is used only rarely. Most use cases don't need
> > to deconstruct a ligature that way; after all, that's what ligatures
> > are for.
>
> In an earlier thread, you mentioned programming font ligatures — wouldn't it be very common to deconstruct such ligatures, like → into ->?
No, I don't think so. Why would this be common?
> Maybe the effect wouldn't be jarring with monospaced fonts, but for these the simple approach of subdividing the glyph works nicely too.
It might work in some simple cases, but I wonder what gains would that
give the users. It sounds very unusual to me to do something like
that, and I don't think we ever heard any such complaints until now,
although prettify-symbols-mode exists for several years.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 2:25 ` Ligatures Eli Zaretskii
@ 2020-05-19 2:44 ` Clément Pit-Claudel
2020-05-19 13:59 ` Ligatures Eli Zaretskii
2020-05-19 3:47 ` Ligatures Stefan Monnier
1 sibling, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-19 2:44 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
On 18/05/2020 22.25, Eli Zaretskii wrote:
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Mon, 18 May 2020 15:44:01 -0400
>>
>>> The idea is that this is used only rarely. Most use cases don't need
>>> to deconstruct a ligature that way; after all, that's what ligatures
>>> are for.
>>
>> In an earlier thread, you mentioned programming font ligatures — wouldn't it be very common to deconstruct such ligatures, like → into ->?
>
> No, I don't think so. Why would this be common?
I thought it would be the default. Emacs shows →, and you can put the point either before (|→), in the middle (-|>), or after (→|).
This is what prettify-symbols-unprettify-at-point exists for, I believe, though it doesn't work perfectly often the composed glyph doesn't have the same width as the non-composed one.
Here's a fairly common case: when writing html or XML, you may type <, then >, then press C-b and type the tag name; or you may use < and a paredit-like setup that inserts the > automatically. If the font has a ligature for <> and you can't put the point in the middle, this breaks. Same for || — the notation |x| { … } is used for lambdas in some languages; if you type || then try to move the point back inside the composed || glyph it won't work.
>> Maybe the effect wouldn't be jarring with monospaced fonts, but for these the simple approach of subdividing the glyph works nicely too.
>
> It might work in some simple cases, but I wonder what gains would that
> give the users. It sounds very unusual to me to do something like
> that, and I don't think we ever heard any such complaints until now,
> although prettify-symbols-mode exists for several years.
I thought I did complain in the past, but I can't find the thread any more :/ prettify-symbols-unprettify-at-point helps, and it's the default in some popular Emacs configs.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 2:25 ` Ligatures Eli Zaretskii
2020-05-19 2:44 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 3:47 ` Stefan Monnier
2020-05-19 4:51 ` Ligatures Clément Pit-Claudel
1 sibling, 1 reply; 145+ messages in thread
From: Stefan Monnier @ 2020-05-19 3:47 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Clément Pit-Claudel, emacs-devel
> It might work in some simple cases, but I wonder what gains would that
> give the users. It sounds very unusual to me to do something like
> that, and I don't think we ever heard any such complaints until now,
> although prettify-symbols-mode exists for several years.
For things like `→`, I think of `->` as an "encoding" used to stay
within the confines of ASCII whereas `→` is what is really "meant".
So when I see `→` I'm not likely to want to "look inside" and am instead
happy if `C-p` skips over both characters at once (except when I want
to change it to `=>`, of course).
In contrast I don't think of "ffi" as the ASCII encoding of `ffi`.
Instead I think of `ffi` as just a more refined way to draw "ffi" and I'd
find it odd for `C-p` to skip over those three chars.
So, the right behavior depends on the intention, AFAICT.
Since 99.99% of my Emacs windows is made up of monospace text,
I probably won't be too significantly affected either way.
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 3:47 ` Ligatures Stefan Monnier
@ 2020-05-19 4:51 ` Clément Pit-Claudel
0 siblings, 0 replies; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-19 4:51 UTC (permalink / raw)
To: Stefan Monnier, Eli Zaretskii; +Cc: emacs-devel
On 18/05/2020 23.47, Stefan Monnier wrote:
> (except when I want
> to change it to `=>`, of course).
Variants of this case are not too uncommon, and they're not always as simple as removing the beginning of the composition to replace it with something else. For example, I'm typing a regexp in javascript, enclosed in /…/; then I add a backslash at the end of the regexp to escape a character that I haven't typed yet, and \/ turns into a composition, and the point disappears. Or I write html, with a buffer that contains <a href>, I type an = sign after the href, and => gets composed into ⇒, and the point disappears. There are many such examples, and if I lose my position, I need to delete part of the composition.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 16:08 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
` (2 preceding siblings ...)
2020-05-18 17:31 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Clément Pit-Claudel
@ 2020-05-19 5:43 ` ASSI
2020-05-19 7:22 ` Ligatures tomas
2020-05-19 14:18 ` Ligatures Eli Zaretskii
3 siblings, 2 replies; 145+ messages in thread
From: ASSI @ 2020-05-19 5:43 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: pipcet, emacs-devel
Eli Zaretskii writes:
> On second thought, I think I misunderstood you. If the font that is
> used shows "ffi" as a _single_ glyph ffi, and LibreOffice indeed
> highlights parts of this glyph, then I'd like to know how it does
> that, and how far does this capability extend. I mean, what does it
> do with ligatures like ae, displayed as æ -- does it highlight the
> common vertical stroke for both parts?
The only program I ever used that I remember doing this (a WYSIWYG TeX
editor for DOS, natch) temporarily broke the ligature while you were
moving the cursor inside. It looked a bit strange and was slightly
distracting if you were just moving the cursor without trying to edit
it, but otherwise did the job well.
I expect that fonts that make extensive use of ligatures have
information on where the ligatures can be broken and exactly how to
display the parts in that case, although I wouldn't be surprised if that
information is not very reliable even when just considering latin family
scripts.
> And what about "st", displayed as st -- this has a curved "hand"
> connecting s and t -- to which of the 2 does it belong for the
> purposes of highlighting? There's also "hv" displayed as ƕ, let alone
> "fs" displayed as ẞ and "fz" displayed as ß.
The origin of this ligature has no general consensus AFAIK, but if you
read older (facsimile) printed literature from around 1800 it becomes
pretty obvious that the typeface evolved from a combination of long s
(mainly used inside a word) and round s (used at the end). The origin
of "sz" in that place is even more complicated to figure out, but it
seems (to me anyway) that this was driven by a desire to preserve the
distinction to double s / "ss" when using typefaces that didn't have the
proper glyphs for the various types of "s" previously available in
Fraktur. Neither "fs" nor "fz" should ligature into "ß" (which is a
proper glyph these days and no longer a ligature, although you are still
allowed to break it into either "ss" or "sz" when using typefaces that
don't support it, like most versalia).
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
Samples for the Waldorf Blofeld:
http://Synth.Stromeko.net/Downloads.html#BlofeldSamplesExtra
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 5:43 ` Ligatures ASSI
@ 2020-05-19 7:22 ` tomas
2020-05-19 7:55 ` Ligatures Joost Kremers
2020-05-19 14:18 ` Ligatures Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: tomas @ 2020-05-19 7:22 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1013 bytes --]
On Tue, May 19, 2020 at 07:43:00AM +0200, ASSI wrote:
[...]
> [...] Neither "fs" nor "fz" should ligature into "ß" (which is a
> proper glyph these days and no longer a ligature, although you are still
> allowed to break it into either "ss" or "sz" when using typefaces that
> don't support it, like most versalia).
Definitely. This "long" and "short" vaiants of s were in use in Germany
early in te twentieth, in Fraktur and also in handwriting [1]. This two
forms of "s" (one for terminal position) still exists in Greek. The
ß "ligature" (which isn't perceived as such nowadays) evolved from
"ss", the first s being a non-terminal (yeah, looks a bit like an "f"
to the untrained eye).
In the German speaking part of Switzerland, "ß" is always replaced by
"ss". There's no capital version of "ß", you use "SS" (thus breaking
bijectivity of upper- and lowercase).
Writing is human. Human is messy :-/
Cheers
[1] https://de.wikipedia.org/wiki/S%C3%BCtterlinschrift
-- tomás
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 7:22 ` Ligatures tomas
@ 2020-05-19 7:55 ` Joost Kremers
2020-05-19 8:07 ` Ligatures tomas
0 siblings, 1 reply; 145+ messages in thread
From: Joost Kremers @ 2020-05-19 7:55 UTC (permalink / raw)
To: tomas; +Cc: emacs-devel
On Tue, May 19 2020, tomas@tuxteam.de wrote:
> There's no capital version of "ß", you use "SS" (thus breaking
> bijectivity of upper- and lowercase).
Actually, uppercase ẞ was accepted into the official German
spelling in 2017:
https://en.wikipedia.org/wiki/Capital_%E1%BA%9E (cf. last line of
Section "History").
--
Joost Kremers
Life has its moments
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 7:55 ` Ligatures Joost Kremers
@ 2020-05-19 8:07 ` tomas
2020-05-19 10:17 ` Ligatures Yuri Khan
2020-05-19 10:43 ` Ligatures Werner LEMBERG
0 siblings, 2 replies; 145+ messages in thread
From: tomas @ 2020-05-19 8:07 UTC (permalink / raw)
To: Joost Kremers; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1054 bytes --]
On Tue, May 19, 2020 at 09:55:25AM +0200, Joost Kremers wrote:
>
> On Tue, May 19 2020, tomas@tuxteam.de wrote:
> >There's no capital version of "ß", you use "SS" (thus breaking
> >bijectivity of upper- and lowercase).
>
> Actually, uppercase ẞ was accepted into the official German spelling
> in 2017:
>
> https://en.wikipedia.org/wiki/Capital_%E1%BA%9E (cf. last line of
> Section "History").
Yes, Officially. Nearly nobody uses it. If I had to bet, I'd expect
'ß' to disappear and be replaced by 'ss', as the Swiss do before
uppercase ß has a chance :-)
But we disgress: I was just trying to highlight how much cultural
bias there is in one's view of seemingly technical things. When
talking ligatures, one should try to first understand what crazy
stuff other languages have to take care of.
I wish I could say a thing or two about Devanagari or Hangul [1],
but knowledge is just too limited.
Cheers
[1] https://en.wikipedia.org/wiki/Hangul
for another example where you stack stuff in two dimensions
-- t
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 17:31 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Clément Pit-Claudel
2020-05-18 17:39 ` Eli Zaretskii
@ 2020-05-19 10:09 ` Trevor Spiteri
2020-05-19 14:22 ` Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: Trevor Spiteri @ 2020-05-19 10:09 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1506 bytes --]
On 18/05/2020 19:31, Clément Pit-Claudel wrote:
> On 18/05/2020 12.08, Eli Zaretskii wrote:
>> On second thought, I think I misunderstood you. If the font that is
>> used shows "ffi" as a _single_ glyph ffi, and LibreOffice indeed
>> highlights parts of this glyph, then I'd like to know how it does
>> that, and how far does this capability extend. I mean, what does it
>> do with ligatures like ae, displayed as æ -- does it highlight the
>> common vertical stroke for both parts? And what about "st", displayed
>> as st -- this has a curved "hand" connecting s and t -- to which of the
>> 2 does it belong for the purposes of highlighting? There's also "hv"
>> displayed as ƕ, let alone "fs" displayed as ẞ and "fz" displayed as
>> ß.
> I've attached a screenshot with a few examples, though I couldn't find a font that displays ae as æ.
>
> Firefox does the same as LibreOffice (try it here, for example: https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant-ligatures). Since Firefox uses Harbuzz, I think there's a good chance we can support that feature too :)
For what it's worth, LibreOffice does it differently. I think what it
does is place the cursor on the position it would be if any following
text was missing. So moving after the second f in ffi would move the
cursor to the same position as after ff if the i was missing. This is
evident from fraction ligatures; in the screenshot I'm attaching, "63"
is selected and the selection matches the 63 in the bottom line.
[-- Attachment #2: fraction.png --]
[-- Type: image/png, Size: 5505 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 8:07 ` Ligatures tomas
@ 2020-05-19 10:17 ` Yuri Khan
2020-05-19 14:26 ` Ligatures Eli Zaretskii
2020-05-19 10:43 ` Ligatures Werner LEMBERG
1 sibling, 1 reply; 145+ messages in thread
From: Yuri Khan @ 2020-05-19 10:17 UTC (permalink / raw)
To: tomas; +Cc: Joost Kremers, Emacs developers
On Tue, 19 May 2020 at 15:11, <tomas@tuxteam.de> wrote:
> [1] https://en.wikipedia.org/wiki/Hangul
> for another example where you stack stuff in two dimensions
An example of character combining other than side-by-side stacking is
much closer than that: Combining diacritics. Sure, you can delete an
acute accent from á by pressing Backspace, but you cannot put point
between the ‘a’ and the accent if you want to put a different
diacritic between them. (And putting multiple diacritics over a single
base character in various orders is a thing, it is the subject of the
Unicode Canonical Order subsection in Unicode standard.)
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 8:07 ` Ligatures tomas
2020-05-19 10:17 ` Ligatures Yuri Khan
@ 2020-05-19 10:43 ` Werner LEMBERG
2020-05-19 10:48 ` Ligatures tomas
1 sibling, 1 reply; 145+ messages in thread
From: Werner LEMBERG @ 2020-05-19 10:43 UTC (permalink / raw)
To: tomas; +Cc: joostkremers, emacs-devel
>> >There's no capital version of "ß", you use "SS" (thus breaking
>> >bijectivity of upper- and lowercase).
>>
>> Actually, uppercase ẞ was accepted into the official German
>> spelling in 2017:
>>
>> https://en.wikipedia.org/wiki/Capital_%E1%BA%9E (cf. last line of
>> Section "History").
>
> Yes, Officially. Nearly nobody uses it. If I had to bet, I'd expect
> 'ß' to disappear and be replaced by 'ss', as the Swiss do before
> uppercase ß has a chance :-)
Well, if your family name is 'Dreßen', you don't want to see your name
written as 'DRESSEN' in your passport (which usually requires
uppercase for family names): All German speakers would pronounce the
first 'e' as a short vowel instead of the correct long one. Exactly
for this situation – and for hardly anything else – you should write
'DREẞEN'.
Werner
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 10:43 ` Ligatures Werner LEMBERG
@ 2020-05-19 10:48 ` tomas
0 siblings, 0 replies; 145+ messages in thread
From: tomas @ 2020-05-19 10:48 UTC (permalink / raw)
To: Werner LEMBERG; +Cc: joostkremers, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 861 bytes --]
On Tue, May 19, 2020 at 12:43:06PM +0200, Werner LEMBERG wrote:
[...]
> Well, if your family name is 'Dreßen', you don't want to see your name
> written as 'DRESSEN' in your passport (which usually requires
> uppercase for family names): All German speakers would pronounce the
> first 'e' as a short vowel instead of the correct long one. Exactly
> for this situation – and for hardly anything else – you should write
> 'DREẞEN'.
Yes, I know -- that's why such things change slowly. But the Swiss
prove that it works. We're used to having things which are written
the same and pronounced differently, anyway. One more wouldn't
change things.
Note that I'm not advocating [1] for dropping the 'ß'. I'm just betting
that it might happen rather sooner than later.
Cheers
[1] I've enough to do advocating free software ;-D
-- t
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-18 21:59 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Alan Third
@ 2020-05-19 13:56 ` Eli Zaretskii
2020-05-19 14:39 ` Clément Pit-Claudel
2020-05-19 20:26 ` Alan Third
0 siblings, 2 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 13:56 UTC (permalink / raw)
To: Alan Third; +Cc: cpitclaudel, emacs-devel
> Date: Mon, 18 May 2020 23:59:11 +0200 (CEST)
> From: Alan Third <alan@idiocy.org>
> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org
>
> In case anyone's interested, I've attached a screenshot of Apple's
> Pages.app displaying the word Zapfino with the cursor after the "a".
I don't see anything on or after "a", I see a thin vertical line on
the "Z". is that what is actually displayed? If so, how do people
know the cursor is after "a"??
> Clearly not ideal. OTOH, if LibreOffice, Firefox, and even Apple's
> products do this, perhaps it's just the way people will expect it to
> be done.
If someone wants to work on such a feature, I'm sure it will be
welcome by at least some of the users.
Thanks.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 2:44 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 13:59 ` Eli Zaretskii
2020-05-19 14:35 ` Ligatures Clément Pit-Claudel
2020-05-19 15:36 ` Ligatures Tassilo Horn
0 siblings, 2 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 13:59 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
> Cc: emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Mon, 18 May 2020 22:44:27 -0400
>
> >> In an earlier thread, you mentioned programming font ligatures — wouldn't it be very common to deconstruct such ligatures, like → into ->?
> >
> > No, I don't think so. Why would this be common?
>
> I thought it would be the default. Emacs shows →, and you can put the point either before (|→), in the middle (-|>), or after (→|).
Doesn't sound as a useful default to me. It could be an optional
feature, though.
> Here's a fairly common case: when writing html or XML, you may type <, then >, then press C-b and type the tag name; or you may use < and a paredit-like setup that inserts the > automatically. If the font has a ligature for <> and you can't put the point in the middle, this breaks. Same for || — the notation |x| { … } is used for lambdas in some languages; if you type || then try to move the point back inside the composed || glyph it won't work.
Sounds like a bug or misfeature that needs a solution, not necessarily
the one that's been proposed here. For example, how about a special
insert command that would disable ligation with the character it
inserts?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 5:43 ` Ligatures ASSI
2020-05-19 7:22 ` Ligatures tomas
@ 2020-05-19 14:18 ` Eli Zaretskii
2020-05-19 14:52 ` Ligatures Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 14:18 UTC (permalink / raw)
To: ASSI; +Cc: pipcet, emacs-devel
> From: ASSI <Stromeko@nexgo.de>
> Cc: pipcet@gmail.com, emacs-devel@gnu.org
> Date: Tue, 19 May 2020 07:43:00 +0200
>
> The only program I ever used that I remember doing this (a WYSIWYG TeX
> editor for DOS, natch) temporarily broke the ligature while you were
> moving the cursor inside. It looked a bit strange and was slightly
> distracting if you were just moving the cursor without trying to edit
> it, but otherwise did the job well.
That's what I had in mind (although I never used such an editor).
> The origin of this ligature has no general consensus AFAIK, but if you
> read older (facsimile) printed literature from around 1800 it becomes
> pretty obvious that the typeface evolved from a combination of long s
> (mainly used inside a word) and round s (used at the end). The origin
> of "sz" in that place is even more complicated to figure out, but it
> seems (to me anyway) that this was driven by a desire to preserve the
> distinction to double s / "ss" when using typefaces that didn't have the
> proper glyphs for the various types of "s" previously available in
> Fraktur. Neither "fs" nor "fz" should ligature into "ß" (which is a
> proper glyph these days and no longer a ligature, although you are still
> allowed to break it into either "ss" or "sz" when using typefaces that
> don't support it, like most versalia).
I think we should support these unusual ligatures for those who'd like
to see them, probably as an opt-in feature.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-19 10:09 ` Trevor Spiteri
@ 2020-05-19 14:22 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 14:22 UTC (permalink / raw)
To: Trevor Spiteri; +Cc: emacs-devel
> From: Trevor Spiteri <tspiteri@ieee.org>
> Date: Tue, 19 May 2020 12:09:32 +0200
>
> For what it's worth, LibreOffice does it differently. I think what it
> does is place the cursor on the position it would be if any following
> text was missing. So moving after the second f in ffi would move the
> cursor to the same position as after ff if the i was missing.
This is only possible if the metrics of a sole f and f inside the
ligature are identical or sufficiently close. That is not generally
true in ligatures, not even in Latin ligatures.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 10:17 ` Ligatures Yuri Khan
@ 2020-05-19 14:26 ` Eli Zaretskii
2020-05-19 19:00 ` Ligatures Yuri Khan
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 14:26 UTC (permalink / raw)
To: Yuri Khan; +Cc: joostkremers, tomas, emacs-devel
> From: Yuri Khan <yuri.v.khan@gmail.com>
> Date: Tue, 19 May 2020 17:17:25 +0700
> Cc: Joost Kremers <joostkremers@fastmail.fm>,
> Emacs developers <emacs-devel@gnu.org>
>
> An example of character combining other than side-by-side stacking is
> much closer than that: Combining diacritics. Sure, you can delete an
> acute accent from á by pressing Backspace, but you cannot put point
> between the ‘a’ and the accent if you want to put a different
> diacritic between them.
Well, you can (this is Emacs, right?): just disable automatic
composition with "M-x auto-composition-mode", and you can do any
editing you want. Then re-enable the mode again.
> (And putting multiple diacritics over a single base character in
> various orders is a thing, it is the subject of the Unicode
> Canonical Order subsection in Unicode standard.)
Canonical order of diacritics is indeed important for jobs such as
comparison, searching, etc. But we are talking about display, and for
display there's a requirement that the order should not matter as long
as the base character comes first. AFAIR, HarfBuzz supports that
requirement, but not every other shaping engine does.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 13:59 ` Ligatures Eli Zaretskii
@ 2020-05-19 14:35 ` Clément Pit-Claudel
2020-05-19 15:21 ` Ligatures Eli Zaretskii
2020-05-19 15:36 ` Ligatures Tassilo Horn
1 sibling, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-19 14:35 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
On 19/05/2020 09.59, Eli Zaretskii wrote:
>> Cc: emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Mon, 18 May 2020 22:44:27 -0400
>>
>>>> In an earlier thread, you mentioned programming font ligatures — wouldn't it be very common to deconstruct such ligatures, like → into ->?
>>>
>>> No, I don't think so. Why would this be common?
>>
>> I thought it would be the default. Emacs shows →, and you can put the point either before (|→), in the middle (-|>), or after (→|).
>
> Doesn't sound as a useful default to me. It could be an optional
> feature, though.
Do we know of other editors that support ligatures but chose not to support moving through a composed character? If not, that would be a fairly strong signal that it's a reasonable default, I'd expect.
>> Here's a fairly common case: when writing html or XML, you may type <, then >, then press C-b and type the tag name; or you may use < and a paredit-like setup that inserts the > automatically. If the font has a ligature for <> and you can't put the point in the middle, this breaks. Same for || — the notation |x| { … } is used for lambdas in some languages; if you type || then try to move the point back inside the composed || glyph it won't work.
>
> Sounds like a bug or misfeature that needs a solution, not necessarily
> the one that's been proposed here.
Possibly! But the feature discussed here seems to fit the bill pretty perfectly, so …
> For example, how about a special
> insert command that would disable ligation with the character it
> inserts?
Would that command be called automatically, or would it require a different input?
I don't think Emacs can guess whether it should enable or disable ligation, so I imagine you mean different input, but that doesn't sound pleasant to use, so maybe I'm misunderstanding?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-19 13:56 ` Eli Zaretskii
@ 2020-05-19 14:39 ` Clément Pit-Claudel
2020-05-19 21:43 ` Pip Cet
2020-05-19 20:26 ` Alan Third
1 sibling, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-19 14:39 UTC (permalink / raw)
To: Eli Zaretskii, Alan Third; +Cc: emacs-devel
On 19/05/2020 09.56, Eli Zaretskii wrote:
> I don't see anything on or after "a", I see a thin vertical line on
> the "Z". is that what is actually displayed? If so, how do people
> know the cursor is after "a"??
They don't: "the seven equal slices that Firefox treats it as for selection/editing purposes don't match up to the visual shapes of the sub-glyphs at all well"
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 14:18 ` Ligatures Eli Zaretskii
@ 2020-05-19 14:52 ` Eli Zaretskii
2020-05-19 15:11 ` Ligatures Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 14:52 UTC (permalink / raw)
To: Stromeko; +Cc: pipcet, emacs-devel
> Date: Tue, 19 May 2020 17:18:41 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: pipcet@gmail.com, emacs-devel@gnu.org
>
> > From: ASSI <Stromeko@nexgo.de>
> > Cc: pipcet@gmail.com, emacs-devel@gnu.org
> > Date: Tue, 19 May 2020 07:43:00 +0200
> >
> > The only program I ever used that I remember doing this (a WYSIWYG TeX
> > editor for DOS, natch) temporarily broke the ligature while you were
> > moving the cursor inside. It looked a bit strange and was slightly
> > distracting if you were just moving the cursor without trying to edit
> > it, but otherwise did the job well.
>
> That's what I had in mind (although I never used such an editor).
Btw, there's one subtle issue that will need to be resolved if we are
to have this feature of "sub-glyph" cursor movement inside composed
characters. The way we currently display the default block cursor is
by simply redrawing the glyph at point in reverse video. So we don't
have a way of displaying a cursor that "covers" only part of a glyph.
To make this happen, we'd probably need to draw the cursor as part of
drawing the glyph foreground and/or background, which is against the
current flow of the display code: we generally first completely draw
the background and foreground of the entire text that needs to be
redrawn, and only then draw the cursor where it should be placed.
Something to figure out by that "Someone" who'd volunteer for the job.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-18 19:38 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 14:55 ` Pip Cet
2020-05-19 15:30 ` Ligatures Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-19 14:55 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
On Mon, May 18, 2020 at 7:40 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:
> > And this is where it gets back to "let's not hardcode the dependency
> > on Harfbuzz and FreeType, because other backends might actually give
> > us the information we need".
>
> Harfbuzz can give us this info: hb_ot_layout_get_ligature_carets
Thanks, I hadn't looked there!
So Harfbuzz provides a non-core API which, after a separate call for
each cluster, allows us to split up a glyph into non-overlapping
bounding boxes of the same height (the information returned is
one-dimensional, and intended for carets, not for Emacs-style box
cursors).
I don't see how that API design is so great we should hardcode
dependencies on it, though I do agree it's sufficient to work with.
Again, this isn't about some exotic use case: I open a buffer, type
"ffi", and hit C-b twice. What should happen?
AFAIU, people are still seriously considering the possibility that all
of "ffi" would be covered by the cursor. I hope I'm misunderstanding
that, because it's so obviously the wrong thing to do in this case.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 14:52 ` Ligatures Eli Zaretskii
@ 2020-05-19 15:11 ` Pip Cet
2020-05-19 15:36 ` Ligatures Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-19 15:11 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Stromeko, emacs-devel
On Tue, May 19, 2020 at 2:52 PM Eli Zaretskii <eliz@gnu.org> wrote:
> Btw, there's one subtle issue that will need to be resolved if we are
> to have this feature of "sub-glyph" cursor movement inside composed
> characters. The way we currently display the default block cursor is
> by simply redrawing the glyph at point in reverse video. So we don't
> have a way of displaying a cursor that "covers" only part of a glyph.
I thought that was what glyph_row->clip was for.
> To make this happen, we'd probably need to draw the cursor as part of
> drawing the glyph foreground and/or background, which is against the
I believe that's a change we should make anyway: late cursor drawing
makes sense on TTYs with physical cursors, but on GUI backends, we
should simply use a special face for drawing the struct glyph a cursor
is on, IMHO.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 14:35 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 15:21 ` Eli Zaretskii
2020-05-19 15:44 ` Ligatures Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 15:21 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
> Cc: emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Tue, 19 May 2020 10:35:50 -0400
>
> > Doesn't sound as a useful default to me. It could be an optional
> > feature, though.
>
> Do we know of other editors that support ligatures but chose not to support moving through a composed character? If not, that would be a fairly strong signal that it's a reasonable default, I'd expect.
OTOH, the current default exists since Emacs 21, so it sounds like a
reasonable default as well.
And I don't think arguing about defaults in Emacs is useful, because
changing the default if you don't like it is easy. We do change the
default behavior slowly, though.
(And please note that we are talking about defaults for a feature that
doesn't yet exist, which makes this dispute even less useful.)
> > For example, how about a special
> > insert command that would disable ligation with the character it
> > inserts?
>
> Would that command be called automatically, or would it require a different input?
You'd invoke it when you either know in advance you don't want the
next character to ligate, or after you saw the ligature to disable the
ligation for the sequence at or before point.
> I don't think Emacs can guess whether it should enable or disable ligation, so I imagine you mean different input, but that doesn't sound pleasant to use, so maybe I'm misunderstanding?
Emacs cannot, but the user can. Thus a separate command.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 14:55 ` Ligatures Pip Cet
@ 2020-05-19 15:30 ` Clément Pit-Claudel
2020-05-19 15:52 ` Ligatures Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-19 15:30 UTC (permalink / raw)
To: Pip Cet; +Cc: emacs-devel
On 19/05/2020 10.55, Pip Cet wrote:
> On Mon, May 18, 2020 at 7:40 PM Clément Pit-Claudel
> <cpitclaudel@gmail.com> wrote:
>>> And this is where it gets back to "let's not hardcode the dependency
>>> on Harfbuzz and FreeType, because other backends might actually give
>>> us the information we need".
>>
>> Harfbuzz can give us this info: hb_ot_layout_get_ligature_carets
>
> Thanks, I hadn't looked there!
>
> So Harfbuzz provides a non-core API which, after a separate call for
> each cluster, allows us to split up a glyph into non-overlapping
> bounding boxes of the same height (the information returned is
> one-dimensional, and intended for carets, not for Emacs-style box
> cursors).
Are you worried about the height of the box? For the width part, isn't it just the difference between two consecutive carets?
> I don't see how that API design is so great we should hardcode
> dependencies on it, though I do agree it's sufficient to work with.
No opinions there ^^
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 15:11 ` Ligatures Pip Cet
@ 2020-05-19 15:36 ` Eli Zaretskii
2020-05-19 16:16 ` Ligatures Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 15:36 UTC (permalink / raw)
To: Pip Cet; +Cc: Stromeko, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Tue, 19 May 2020 15:11:27 +0000
> Cc: Stromeko@nexgo.de, emacs-devel@gnu.org
>
> On Tue, May 19, 2020 at 2:52 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > Btw, there's one subtle issue that will need to be resolved if we are
> > to have this feature of "sub-glyph" cursor movement inside composed
> > characters. The way we currently display the default block cursor is
> > by simply redrawing the glyph at point in reverse video. So we don't
> > have a way of displaying a cursor that "covers" only part of a glyph.
>
> I thought that was what glyph_row->clip was for.
We could use that, but that's not the main problem. After all,
clipping while drawing is simple and doesn't need any special help.
The problem is that we need to change how the cursor is drawn, from
the control flow POV. We'd need to audit the code and see that the
information required for drawing the cursor is available when we are
drawing the text. And then there's the popular use case where nothing
changes except the cursor position, in which case no text is redrawn
at all.
> > To make this happen, we'd probably need to draw the cursor as part of
> > drawing the glyph foreground and/or background, which is against the
>
> I believe that's a change we should make anyway: late cursor drawing
> makes sense on TTYs with physical cursors, but on GUI backends, we
> should simply use a special face for drawing the struct glyph a cursor
> is on, IMHO.
It cannot be a single face, because the "thing under cursor" can be
anything, and can have different colors. We will need to merge faces,
which is slower than the current simple but effective method, which
completely sidesteps the issue.
in any case, using a face doesn't solve the main problem, as we'd
still need to draw the glyph with partial colors.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 13:59 ` Ligatures Eli Zaretskii
2020-05-19 14:35 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 15:36 ` Tassilo Horn
2020-05-19 16:08 ` Ligatures Eli Zaretskii
2020-05-19 16:14 ` Ligatures Stefan Monnier
1 sibling, 2 replies; 145+ messages in thread
From: Tassilo Horn @ 2020-05-19 15:36 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Clément Pit-Claudel, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1835 bytes --]
Eli Zaretskii <eliz@gnu.org> writes:
>> > it be very common to deconstruct such ligatures, like → into ->?
>> >
>> > No, I don't think so. Why would this be common?
>>
>> I thought it would be the default. Emacs shows →, and you can put the
>> point either before (|→), in the middle (-|>), or after (→|).
>
> Doesn't sound as a useful default to me. It could be an optional
> feature, though.
To me it sounds like a good default.
>> Here's a fairly common case: when writing html or XML, you may type
>> <, then >, then press C-b and type the tag name; or you may use < and
>> a paredit-like setup that inserts the > automatically. If the font
>> has a ligature for <> and you can't put the point in the middle, this
>> breaks. Same for || — the notation |x| { … } is used for lambdas in
>> some languages; if you type || then try to move the point back inside
>> the composed || glyph it won't work.
>
> Sounds like a bug or misfeature that needs a solution, not necessarily
> the one that's been proposed here. For example, how about a special
> insert command that would disable ligation with the character it
> inserts?
I use the attached self-written ligature.el (Eli, you've helped me with
that some months back). That's all nice but sometimes I too have the
problem that I want to edit the name of a "private" function/variable
foo--do-stuff and cannot move point inside the double-dash because it is
composed as one char. As a little cure, I disable ligatures in the
minibuffer where I absolutely need to do completion stuff like
foo-<TAB>-bar.
Another case is where when inserting < automatically inserts >
immediately giving a <> diamond where I cannot move into.
A special insert command will not help here because it is already
inserted.
Bye,
Tassilo
[-- Attachment #2: ligature.el --]
[-- Type: text/plain, Size: 3251 bytes --]
(defgroup ligature nil
"Support for font ligatures"
:version "28.1"
:prefix "ligature-")
(defcustom ligature-arrows
(list "-->" "<!--" "->>" "<<-" "->" "<-"
"<-<" ">>-" ">-" "<~>" "-<" "-<<"
"<=>" "=>" "<=<" "<<=" "<==" "<==>" "==>" "=>>" ">=>" ">>="
"<-|" "<=|" "|=>" "|->" "<~~" "<~" "~~>"
"~>" "<->")
"Arrow ligatures."
:type '(repeat string))
(defcustom ligature-misc
(list "..<" "~-" "-~" "~@" "-|" "_|_" "|-" "||-" "|=" "||="
".?" "?=" "<|>" "<:" ":<" ":>" ">:"
".=" ".-" "__" "<<<" ">>>" "<<" ">>" "~~"
"<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" "<*" "*>" "</" "</>" "/>"
"|}" "{|" "[<" ">]" ":?>" ":?" "[||]" "?:" "?."
"|>" "<|" "||>" "<||" "|||>" "<|||::=" "|]" "[|"
"#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" "#!" "#=")
"Miscellaneous ligatures."
:type '(repeat string))
(defcustom ligature-relations
(list "==" "!=" "<=" ">=" "=:=" "!==" "===" "<>" "/==" "=!=" "=/=" "~=" ":="
"/=" "^=")
"Relation ligatures."
:type '(repeat string))
(defcustom ligature-operators
(list "&&" "&&&" "||" "++" "--" "!!" "::" "+++" "??" ":::" "***" "---"
"/\\" "\\/")
"Operator ligatures."
:type '(repeat string))
(defcustom ligature-comments-c-like
(list "//" "///" "/**" "/*" "*/")
"Ligatures for comments in C-like languages."
:type '(repeat string))
(defcustom ligature-comments-xml-like
(list "<!--" "-->")
"Ligatures for comments in XML-like languages."
:type '(repeat string))
(defcustom ligature-hashes
(list "##" "###" "####")
"Ligatures for comments in languages with # being the comment character."
:type '(repeat string))
(defcustom ligature-dots
(list "..." "..")
"Dot ligatures."
:type '(repeat string))
(defcustom ligature-semicolons
(list ";;" ";;;")
"Ligatures for comments in lisp languages."
:type '(repeat string))
(defun ligature--get-all ()
(append ligature-arrows
ligature-relations
ligature-operators
ligature-misc
ligature-dots
ligature-comments-c-like
ligature-comments-xml-like
ligature-hashes
ligature-semicolons))
(defun ligature--apply (ligatures)
(let ((groups (seq-group-by #'string-to-char ligatures)))
(dolist (group groups)
(let ((c (car group))
(rx (regexp-opt (mapcar (lambda (s) (substring s 1))
(cdr group)))))
(set-char-table-range composition-function-table
c `([,(concat "." rx) 0 compose-gstring-for-graphic]))))))
(define-minor-mode ligature-minor-mode
"A mode for font ligatures."
nil "" nil
(if ligature-minor-mode
(progn
(when (minibufferp)
(error "Cannot use ligature-minor-mode in minibuffer"))
;; FIXME: This doesn't work. When enabled, there will be a local
;; variable but the global value is the same (and also includes the
;; ligature composition rules).
(ligature--apply (ligature--get-all)))
;; FIXME: Even if the above worked, this could remove much more than this
;; mode added itself.
(kill-local-variable 'composition-function-table)))
(defun ligature-minor-mode--apply-if-possible ()
(unless (minibufferp)
(ligature-minor-mode)))
(define-globalized-minor-mode global-ligature-minor-mode
ligature-minor-mode
ligature-minor-mode--apply-if-possible)
(provide 'ligature)
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 15:21 ` Ligatures Eli Zaretskii
@ 2020-05-19 15:44 ` Clément Pit-Claudel
2020-05-19 16:15 ` Ligatures Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-19 15:44 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
On 19/05/2020 11.21, Eli Zaretskii wrote:
> And I don't think arguing about defaults in Emacs is useful, because
> changing the default if you don't like it is easy. We do change the
> default behavior slowly, though.
I see this argument often (changing settings is easy), but I don't find it very convincing: in my experience, even after years of using Emacs, figuring which variable controls a given behavior, if there is even such a variable, is usually not easy: it requires reading manuals, guessing the right keywords, and often stepping through function implementations.
It's quite a bit easier in Emacs than in other editors, but still not easy at all.
>>> For example, how about a special
>>> insert command that would disable ligation with the character it
>>> inserts?
>>
>> Would that command be called automatically, or would it require a different input?
>
> You'd invoke it when you either know in advance you don't want the
> next character to ligate, or after you saw the ligature to disable the
> ligation for the sequence at or before point.
That assumes that I know whether inserting a character will introduce a ligation, but I usually don't. I can't keep in my head a list of all the ligatures that my font supports, so I'm bound to be surprised from time to time (besides, this is very contextual. When I write a language where /\ and \/ are used to mean "and" and "or", I think of it when I type a / or a \. But when I'm in a context where /…/ is used to delimit regular expressions and \ is used to escape a character, I don't think of the \/ ligature.
>> I don't think Emacs can guess whether it should enable or disable ligation, so I imagine you mean different input, but that doesn't sound pleasant to use, so maybe I'm misunderstanding?
>
> Emacs cannot, but the user can. Thus a separate command.
I don't think that will work, but maybe I'm missing something. How does this work if I open a file that already has a ligature and I want to modify it? Do I have to explicitly break the ligature before I can edit it?
More importantly, though, I don't understand what problem it would solve, at least in the context of programming ligatures. What is the problem with allowing cursor movement through ligatures like → for ->?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 15:30 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 15:52 ` Pip Cet
0 siblings, 0 replies; 145+ messages in thread
From: Pip Cet @ 2020-05-19 15:52 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1422 bytes --]
On Tue, May 19, 2020 at 3:30 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:
> > So Harfbuzz provides a non-core API which, after a separate call for
> > each cluster, allows us to split up a glyph into non-overlapping
> > bounding boxes of the same height (the information returned is
> > one-dimensional, and intended for carets, not for Emacs-style box
> > cursors).
>
> Are you worried about the height of the box? For the width part, isn't it just the difference between two consecutive carets?
That's what I'd work with, yeah.
Perhaps I can make things a little clearer by attaching a screenshot
of how things currently look with the "Linux Libertine Display O"
font, which has especially prominent ligatures and overhangs (I guess
it's somehow inspired by the operating system kernel it's named for?).
I think there's plenty to be improved about that: use a ligature,
sure, but also maybe get away from the "invert a box" style of drawing
the cursor, or handle overhangs specially, or...something.
But that would require an idea of which pixels belong to which
(sub)glyphs (in the ligature). And caret positioning doesn't give us
enough information to do that.
Thank you again for pointing out that API! Whether it's a core feature
of a shaper or a backend-dependent extra feature is a secondary
concern, the important part is that it's there and we can do the right
thing.
[-- Attachment #2: ffi.jpg --]
[-- Type: image/jpeg, Size: 1741 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 15:36 ` Ligatures Tassilo Horn
@ 2020-05-19 16:08 ` Eli Zaretskii
2020-05-19 16:14 ` Ligatures Stefan Monnier
1 sibling, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 16:08 UTC (permalink / raw)
To: Tassilo Horn; +Cc: cpitclaudel, emacs-devel
> From: Tassilo Horn <tsdh@gnu.org>
> Cc: Clément Pit-Claudel <cpitclaudel@gmail.com>,
> emacs-devel@gnu.org
> Date: Tue, 19 May 2020 17:36:44 +0200
>
> I use the attached self-written ligature.el (Eli, you've helped me with
> that some months back). That's all nice but sometimes I too have the
> problem that I want to edit the name of a "private" function/variable
> foo--do-stuff and cannot move point inside the double-dash because it is
> composed as one char. As a little cure, I disable ligatures in the
> minibuffer where I absolutely need to do completion stuff like
> foo-<TAB>-bar.
>
> Another case is where when inserting < automatically inserts >
> immediately giving a <> diamond where I cannot move into.
Yes, the user-level (and perhaps also some infrastructure level) of
support for ligatures is not yet ready. There's a TODO item for that,
patches are welcome.
> A special insert command will not help here because it is already
> inserted.
Then maybe we need both a command to insert a character without
ligation, and a command to disassemble a ligature at point.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 15:36 ` Ligatures Tassilo Horn
2020-05-19 16:08 ` Ligatures Eli Zaretskii
@ 2020-05-19 16:14 ` Stefan Monnier
1 sibling, 0 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-19 16:14 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Clément Pit-Claudel, emacs-devel
>> Doesn't sound as a useful default to me. It could be an optional
>> feature, though.
> To me it sounds like a good default.
For `->` and `ffi` it sounds good, indeed. For prettify-symbol-mode's
combining of `lambda` into `λ`, OTOH that would be rather undesirable.
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 15:44 ` Ligatures Clément Pit-Claudel
@ 2020-05-19 16:15 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 16:15 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: emacs-devel
> Cc: emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Tue, 19 May 2020 11:44:31 -0400
>
> > You'd invoke it when you either know in advance you don't want the
> > next character to ligate, or after you saw the ligature to disable the
> > ligation for the sequence at or before point.
>
> That assumes that I know whether inserting a character will
> introduce a ligation, but I usually don't. [...]
Did you miss the part after "or after"?
> I don't think that will work, but maybe I'm missing something. How does this work if I open a file that already has a ligature and I want to modify it? Do I have to explicitly break the ligature before I can edit it?
"M-x toggle-ligature-mode RET", perhaps? Or go to the ligature you
want to edit and invoke that command I mentioned above (after "or
after")?
> More importantly, though, I don't understand what problem it would solve, at least in the context of programming ligatures. What is the problem with allowing cursor movement through ligatures like → for ->?
It doesn't feel right to me, and it goes against what Emacs did for
the past 20 years. But that's me.
But again, this is a purely academic argument. Ligature support in
Emacs is not yet ready for prime time, the sub-glyph cursor motion
needs to be implemented in the display engine, and only after that it
would make sense arguing about the defaults of this imaginary mode.
Let's not finish arguing now, lest we will have nothing to argue about
then, okay? ;-)
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 15:36 ` Ligatures Eli Zaretskii
@ 2020-05-19 16:16 ` Pip Cet
2020-05-19 16:41 ` Ligatures Eli Zaretskii
2020-05-19 17:00 ` Ligatures Eli Zaretskii
0 siblings, 2 replies; 145+ messages in thread
From: Pip Cet @ 2020-05-19 16:16 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Stromeko, emacs-devel
On Tue, May 19, 2020 at 3:36 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Tue, 19 May 2020 15:11:27 +0000
> > Cc: Stromeko@nexgo.de, emacs-devel@gnu.org
> >
> > On Tue, May 19, 2020 at 2:52 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > > Btw, there's one subtle issue that will need to be resolved if we are
> > > to have this feature of "sub-glyph" cursor movement inside composed
> > > characters. The way we currently display the default block cursor is
> > > by simply redrawing the glyph at point in reverse video. So we don't
> > > have a way of displaying a cursor that "covers" only part of a glyph.
> >
> > I thought that was what glyph_row->clip was for.
>
> We could use that, but that's not the main problem.
Sorry, I genuinely don't understand what the problem is. draw_glyphs
is called by draw_phys_cursor_glyph, so all we need is a line or two
of extra code in draw_phys_cursor_glyphs to set row->clip to the
rectangle surrounding the subglyph the cursor is on. No further change
of the display engine is required for that, is it?
> The problem is that we need to change how the cursor is drawn, from
> the control flow POV.
That's a separate thing that, yes, we need to do. Because optimizing
for TTYs is no longer appropriate. But I don't see why we need to
perform this large change before performing the little one that makes
things work for subglyphs.
> We'd need to audit the code and see that the
> information required for drawing the cursor is available when we are
> drawing the text. And then there's the popular use case where nothing
> changes except the cursor position, in which case no text is redrawn
> at all.
Except for the glyphs the cursor is on, right? Those are redrawn by
draw_phys_cursor_glyph, or am I missing something here?
> > > To make this happen, we'd probably need to draw the cursor as part of
> > > drawing the glyph foreground and/or background, which is against the
> >
> > I believe that's a change we should make anyway: late cursor drawing
> > makes sense on TTYs with physical cursors, but on GUI backends, we
> > should simply use a special face for drawing the struct glyph a cursor
> > is on, IMHO.
>
> It cannot be a single face, because the "thing under cursor" can be
> anything, and can have different colors.
Agreed.
> We will need to merge faces,
> which is slower than the current simple but effective method, which
> completely sidesteps the issue.
I believe performance concerns are an entirely different subject (put
briefly, my opinion is that we've painted ourselves into a corner by
micro-optimizing fast loops over an essentially inefficient basic
design).
> in any case, using a face doesn't solve the main problem, as we'd
> still need to draw the glyph with partial colors.
Which we can do by setting glyph_row->clip? I don't see how there's
any problem here at all.
Again, I see three totally separate problems here:
1. draw a box cursor over a partial glyph
2. improve the display engine to handle cursor(s) like other
highlighting on graphical terminals
3. identify and counteract actual performance problems in the redisplay engine
I still don't see how (1) depends on (2), and I think I disagree with
you on the subject of (3), because I think we need to fix the design
first, moving a lot of C code out to Lisp, then see where things
actually chafe and maybe move some special code back to C.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 16:16 ` Ligatures Pip Cet
@ 2020-05-19 16:41 ` Eli Zaretskii
2020-05-19 17:00 ` Ligatures Eli Zaretskii
1 sibling, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 16:41 UTC (permalink / raw)
To: Pip Cet; +Cc: Stromeko, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Tue, 19 May 2020 16:16:53 +0000
> Cc: Stromeko@nexgo.de, emacs-devel@gnu.org
>
> I think we need to fix the design first, moving a lot of C code out
> to Lisp
No, we don't need to fix the design of the display engine. We need to
design a new and different display engine, based on ideas more
flexible and powerful than the current rectangular array of glyphs.
You (or someone else) is more than welcome to work on such a new
design, present it here, discuss ideas, etc. If I can help, I will.
I will reserve my judgment on the "move to Lisp" part until I see the
overall design of this new engine, and at least some of the
implementation ideas, including how not to lose existing display
features.
By contrast, "fixing the design" of the current display engine, let
alone moving parts of it to Lisp, is IMNSHO a waste of effort. It
simply cannot be fixed, it's already stretched beyond limit. We can
(and do) make small adjustments, but that's all.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 16:16 ` Ligatures Pip Cet
2020-05-19 16:41 ` Ligatures Eli Zaretskii
@ 2020-05-19 17:00 ` Eli Zaretskii
1 sibling, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-19 17:00 UTC (permalink / raw)
To: Pip Cet; +Cc: Stromeko, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Tue, 19 May 2020 16:16:53 +0000
> Cc: Stromeko@nexgo.de, emacs-devel@gnu.org
>
> Sorry, I genuinely don't understand what the problem is.
There's no need to argue. There's a TODO item regarding ligature
support, and I just updated it with the ideas from this discussion.
You, or anyone else, are welcome to work on some or all of that. I
think good ligature support in Emacs is long overdue; that is one of
the reasons we added HarfBuzz support and are steadily moving towards
making it the default font backend. Any advances in the direction of
letting Emacs use advanced features of modern fonts are welcome.
> draw_glyphs is called by draw_phys_cursor_glyph, so all we need is a
> line or two of extra code in draw_phys_cursor_glyphs to set
> row->clip to the rectangle surrounding the subglyph the cursor is
> on. No further change of the display engine is required for that, is
> it?
Feel free to ignore me. I may be completely wrong about this. Please
disregard what I said and just code away what you think is needed to
implement this.
> > And then there's the popular use case where nothing
> > changes except the cursor position, in which case no text is redrawn
> > at all.
>
> Except for the glyphs the cursor is on, right? Those are redrawn by
> draw_phys_cursor_glyph, or am I missing something here?
Basically, yes, draw_phys_cursor_glyph. But there are other functions
related to that, and which ones need to be changed for this "partial"
cursor drawing to work, I really don't know/remember, sorry. You need
to read the code.
> > We will need to merge faces,
> > which is slower than the current simple but effective method, which
> > completely sidesteps the issue.
>
> I believe performance concerns are an entirely different subject (put
> briefly, my opinion is that we've painted ourselves into a corner by
> micro-optimizing fast loops over an essentially inefficient basic
> design).
The current design is that faces are realized lazily and cached for
subsequent use, because realizing a face is expensive. It makes no
sense to realize a face each time we blink the cursor. No matter what
you think about the current design, code which does unnecessary
calculations is bad code. Gerd Moellmann, which designed and
implemented the current display engine, isn't stupid or incompetent,
quite the contrary.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 14:26 ` Ligatures Eli Zaretskii
@ 2020-05-19 19:00 ` Yuri Khan
0 siblings, 0 replies; 145+ messages in thread
From: Yuri Khan @ 2020-05-19 19:00 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Joost Kremers, tomas, Emacs developers
> > (And putting multiple diacritics over a single base character in> > various orders is a thing, it is the subject of the Unicode
> > Canonical Order subsection in Unicode standard.)
>
> Canonical order of diacritics is indeed important for jobs such as
> comparison, searching, etc. But we are talking about display, and for
> display there's a requirement that the order should not matter as long
> as the base character comes first. AFAIR, HarfBuzz supports that
> requirement, but not every other shaping engine does.
I meant, the Canonical Order spec could be a lot simpler (“just sort
all diacritics according to their codepoint value” rather than “take
great care to only swap two adjacent diacritics if their combining
classes differ and ordered wrongly”) if diacritics order did not
matter. But it does; <a> <acute> <diaeresis> is different from <a>
<diaeresis> <acute>, so the use case of putting point between the base
character and its following diacritic in order to insert a different
one is somewhat important. Indeed, toggling auto-composition-mode
solves that.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-19 13:56 ` Eli Zaretskii
2020-05-19 14:39 ` Clément Pit-Claudel
@ 2020-05-19 20:26 ` Alan Third
1 sibling, 0 replies; 145+ messages in thread
From: Alan Third @ 2020-05-19 20:26 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, emacs-devel
On Tue, May 19, 2020 at 04:56:32PM +0300, Eli Zaretskii wrote:
> > Date: Mon, 18 May 2020 23:59:11 +0200 (CEST)
> > From: Alan Third <alan@idiocy.org>
> > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org
> >
> > In case anyone's interested, I've attached a screenshot of Apple's
> > Pages.app displaying the word Zapfino with the cursor after the "a".
>
> I don't see anything on or after "a", I see a thin vertical line on
> the "Z". is that what is actually displayed? If so, how do people
> know the cursor is after "a"??
Yep, that's what's displayed. The vertical line is the cursor. The
only reason I know it's after the a is because I hit the right arrow
twice to get there from the left of the glyph.
--
Alan Third
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-19 14:39 ` Clément Pit-Claudel
@ 2020-05-19 21:43 ` Pip Cet
2020-05-20 1:41 ` Clément Pit-Claudel
` (3 more replies)
0 siblings, 4 replies; 145+ messages in thread
From: Pip Cet @ 2020-05-19 21:43 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: Eli Zaretskii, Alan Third, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1433 bytes --]
On Tue, May 19, 2020 at 2:39 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:
> On 19/05/2020 09.56, Eli Zaretskii wrote:
> > I don't see anything on or after "a", I see a thin vertical line on
> > the "Z". is that what is actually displayed? If so, how do people
> > know the cursor is after "a"??
>
> They don't: "the seven equal slices that Firefox treats it as for selection/editing purposes don't match up to the visual shapes of the sub-glyphs at all well"
And I'm afraid the difference is much more obvious with box cursors
than it is with carets. I'm attaching a screenshot of a patched Emacs
displaying "ffi", with point on the second f, in the "Linux Libertine
Display O" font (using approximately equal slices).
I think this is a bit of a worst-case scenario, a three-letter
ligature in a font using ligatures and overhangs very
enthusiastically. It might be okay for other fonts.
My remaining idea is to stretch characters so we can break up a
ligature without changing its total width. I'm not sure how to do
that, though.
(I'm also attaching the patch, for the morbidly curious; it isn't
clean, readable, or finished in any way, and contains at least one
obvious bug. It's just good enough to produce the screenshot, and
maybe it can serve as a hint as to which files need changing for
ligatures to work; but such changes would have to be done very
differently from the patch.).
[-- Attachment #2: ffi-box-cursor.png --]
[-- Type: image/png, Size: 1067 bytes --]
[-- Attachment #3: 0001-Ligatures.diff --]
[-- Type: text/x-patch, Size: 21370 bytes --]
diff --git a/src/alloc.c b/src/alloc.c
index ebc55857ea..1395f647f4 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -322,7 +322,7 @@ #define PUREBEG (char *) pure
/* If positive, garbage collection is inhibited. Otherwise, zero. */
-static intptr_t garbage_collection_inhibited;
+static intptr_t garbage_collection_inhibited = 3;
/* The GC threshold in bytes, the last time it was calculated
from gc-cons-threshold and gc-cons-percentage. */
diff --git a/src/composite.c b/src/composite.c
index 518502be49..e2bece40c8 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -836,7 +836,7 @@ fill_gstring_body (Lisp_Object gstring)
LGLYPH_SET_CHAR (g, c);
if (font != NULL)
- code = font->driver->encode_char (font, LGLYPH_CHAR (g));
+ code = font->driver->encode_char (font, LGLYPH_CHAR (g), NULL);
else
code = FONT_INVALID_CODE;
if (code != FONT_INVALID_CODE)
diff --git a/src/dispextern.h b/src/dispextern.h
index 0b1f3d14ae..2f6b33e74c 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -397,6 +397,15 @@ #define SET_GLYPH_FROM_GLYPH_CODE(glyph, gc) \
};
+struct glyph_context
+{
+ union vectorlike_header header;
+ Lisp_Object string;
+ Lisp_Object position;
+ int i;
+ int n;
+};
+
/* Glyphs.
Be extra careful when changing this structure! Esp. make sure that
@@ -567,6 +576,8 @@ #define FACE_ID_BITS 20
/* Used to compare all bit-fields above in one step. */
unsigned val;
} u;
+
+ struct glyph_context *context;
};
diff --git a/src/font.c b/src/font.c
index ab00402b40..8de3c969b9 100644
--- a/src/font.c
+++ b/src/font.c
@@ -3010,7 +3010,7 @@ font_has_char (struct frame *f, Lisp_Object font, int c)
if (result >= 0)
return result;
}
- return (fontp->driver->encode_char (fontp, c) != FONT_INVALID_CODE);
+ return (fontp->driver->encode_char (fontp, c, NULL) != FONT_INVALID_CODE);
}
@@ -3023,7 +3023,7 @@ font_encode_char (Lisp_Object font_object, int c)
eassert (FONT_OBJECT_P (font_object));
font = XFONT_OBJECT (font_object);
- return font->driver->encode_char (font, c);
+ return font->driver->encode_char (font, c, NULL);
}
@@ -4418,7 +4418,7 @@ font_fill_lglyph_metrics (Lisp_Object glyph, struct font *font, unsigned int cod
struct font_metrics metrics;
LGLYPH_SET_CODE (glyph, code);
- font->driver->text_extents (font, &code, 1, &metrics);
+ font->driver->text_extents (font, &code, 1, &metrics, NULL);
LGLYPH_SET_LBEARING (glyph, metrics.lbearing);
LGLYPH_SET_RBEARING (glyph, metrics.rbearing);
LGLYPH_SET_WIDTH (glyph, metrics.width);
@@ -4638,7 +4638,7 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 2, 0,
struct face *face = FACE_FROM_ID (f, face_id);
if (! face->font)
return Qnil;
- unsigned code = face->font->driver->encode_char (face->font, c);
+ unsigned code = face->font->driver->encode_char (face->font, c, NULL);
if (code == FONT_INVALID_CODE)
return Qnil;
Lisp_Object font_object;
@@ -4965,7 +4965,7 @@ DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0,
unsigned code;
struct font_metrics metrics;
- code = font->driver->encode_char (font, c);
+ code = font->driver->encode_char (font, c, NULL);
if (code == FONT_INVALID_CODE)
{
ASET (vec, i, Qnil);
@@ -4976,7 +4976,7 @@ DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0,
LGLYPH_SET_TO (g, i);
LGLYPH_SET_CHAR (g, c);
LGLYPH_SET_CODE (g, code);
- font->driver->text_extents (font, &code, 1, &metrics);
+ font->driver->text_extents (font, &code, 1, &metrics, NULL);
LGLYPH_SET_WIDTH (g, metrics.width);
LGLYPH_SET_LBEARING (g, metrics.lbearing);
LGLYPH_SET_RBEARING (g, metrics.rbearing);
diff --git a/src/font.h b/src/font.h
index 8614e7fa10..952a9fa4c3 100644
--- a/src/font.h
+++ b/src/font.h
@@ -565,6 +565,8 @@ #define FONT_PIXEL_SIZE_QUANTUM 1
#define FONT_INVALID_CODE 0xFFFFFFFF
+struct glyph_context;
+
/* Font driver. Members specified as "optional" can be NULL. */
struct font_driver
@@ -645,14 +647,15 @@ #define FONT_INVALID_CODE 0xFFFFFFFF
/* Return a glyph code of FONT for character C (Unicode code point).
If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
- unsigned (*encode_char) (struct font *font, int c);
+ unsigned (*encode_char) (struct font *font, int c, struct glyph_context *context);
/* Compute the total metrics of the NGLYPHS glyphs specified by
the font FONT and the sequence of glyph codes CODE, and store the
result in METRICS. */
void (*text_extents) (struct font *font,
const unsigned *code, int nglyphs,
- struct font_metrics *metrics);
+ struct font_metrics *metrics,
+ struct glyph_context *context);
#ifdef HAVE_WINDOW_SYSTEM
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 7832d4f5ce..19c2644285 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -323,7 +323,7 @@ ftcrfont_has_char (Lisp_Object font, int c)
}
static unsigned
-ftcrfont_encode_char (struct font *font, int c)
+ftcrfont_encode_char (struct font *font, int c, struct glyph_context *context)
{
struct font_info *ftcrfont_info = (struct font_info *) font;
unsigned code = FONT_INVALID_CODE;
@@ -331,20 +331,53 @@ ftcrfont_encode_char (struct font *font, int c)
int utf8len = CHAR_STRING (c, utf8);
cairo_glyph_t stack_glyph;
cairo_glyph_t *glyphs = &stack_glyph;
- int num_glyphs = 1;
- if (cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font, 0, 0,
- (char *) utf8, utf8len,
- &glyphs, &num_glyphs,
- NULL, NULL, NULL)
- == CAIRO_STATUS_SUCCESS)
+ if (context == NULL)
{
- if (glyphs != &stack_glyph)
- cairo_glyph_free (glyphs);
- else if (stack_glyph.index)
- code = stack_glyph.index;
+ context = xmalloc (sizeof *context);
+ context->string = CALLN (Fstring, make_fixnum (c));
+ context->position = make_fixnum (0);
}
+ unsigned int num_glyphs = 0;
+ unsigned int num_clusters = 0;
+ hb_buffer_t *hb_buf = hb_buffer_create ();
+ hb_buffer_set_cluster_level (hb_buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
+ hb_buffer_add_utf8 (hb_buf, SDATA (context->string), -1, 0, -1);
+ hb_buffer_set_direction (hb_buf, HB_DIRECTION_LTR);
+ hb_font_t *hb_font = hb_ft_font_create_referenced
+ (cairo_ft_scaled_font_lock_face (ftcrfont_info->cr_scaled_font));
+ hb_shape (hb_font, hb_buf, NULL, 0);
+ hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos
+ (hb_buf, &num_glyphs);
+ hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions
+ (hb_buf, &num_glyphs);
+ int i0, i1;
+ int c0, c1;
+ i0 = 0;
+ for (int i = num_glyphs - 1; i >= 0; i--)
+ {
+ if (glyph_info[i].cluster <= XFIXNUM (context->position))
+ {
+ i0 = i;
+ c0 = glyph_info[i].cluster;
+ break;
+ }
+ }
+ i1 = num_glyphs;
+ for (int i = 0; i < num_glyphs; i++)
+ {
+ if (glyph_info[i].cluster > c0)
+ {
+ i1 = i;
+ c1 = glyph_info[i].cluster;
+ break;
+ }
+ }
+ context->i = XFIXNUM (context->position) - c0;
+ context->n = c1 - c0;
+ code = glyph_info[i0].codepoint;
+
return code;
}
@@ -352,30 +385,65 @@ ftcrfont_encode_char (struct font *font, int c)
ftcrfont_text_extents (struct font *font,
const unsigned *code,
int nglyphs,
- struct font_metrics *metrics)
+ struct font_metrics *metrics,
+ struct glyph_context *context)
{
+ struct font_info *ftcrfont_info = (struct font_info *) font;
int width, i;
block_input ();
- width = ftcrfont_glyph_extents (font, code[0], metrics);
- for (i = 1; i < nglyphs; i++)
+
+ if (context == NULL)
{
- struct font_metrics m;
- int w = ftcrfont_glyph_extents (font, code[i], metrics ? &m : NULL);
+ context = xmalloc (sizeof *context);
+ context->string = CALLN (Fstring, make_fixnum (code[0]));
+ context->position = make_fixnum (0);
+ }
- if (metrics)
+ unsigned int num_glyphs = 0;
+ unsigned int num_clusters = 0;
+ hb_buffer_t *hb_buf = hb_buffer_create ();
+ hb_buffer_set_cluster_level (hb_buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
+ hb_buffer_set_direction (hb_buf, HB_DIRECTION_LTR);
+ hb_buffer_set_content_type (hb_buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
+ int n = 0;
+ for (const char *p = SDATA (context->string); p <= SDATA (context->string) + SBYTES (context->string);)
+ {
+ int c = string_char_advance (&p);
+ hb_buffer_add (hb_buf, c, n++);
+ }
+ hb_font_t *hb_font = hb_ft_font_create_referenced
+ (cairo_ft_scaled_font_lock_face (ftcrfont_info->cr_scaled_font));
+ hb_shape (hb_font, hb_buf, NULL, 0);
+ hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos
+ (hb_buf, &num_glyphs);
+ hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions
+ (hb_buf, &num_glyphs);
+ int i0, i1;
+ int c0, c1;
+ i0 = 0;
+ for (int i = num_glyphs - 1; i >= 0; i--)
+ {
+ if (glyph_info[i].cluster <= XFIXNUM (context->position))
+ {
+ i0 = i;
+ c0 = glyph_info[i].cluster;
+ break;
+ }
+ }
+ i1 = num_glyphs;
+ for (int i = 0; i < num_glyphs; i++)
+ {
+ if (glyph_info[i].cluster > c0)
{
- if (width + m.lbearing < metrics->lbearing)
- metrics->lbearing = width + m.lbearing;
- if (width + m.rbearing > metrics->rbearing)
- metrics->rbearing = width + m.rbearing;
- if (m.ascent > metrics->ascent)
- metrics->ascent = m.ascent;
- if (m.descent > metrics->descent)
- metrics->descent = m.descent;
+ i1 = i;
+ c1 = glyph_info[i].cluster;
+ break;
}
- width += w;
}
+ context->i = XFIXNUM (context->position) - c0;
+ context->n = c1 - c0;
+ width = glyph_pos[i0].x_advance / (c1 - c0) / 64;
unblock_input ();
if (metrics)
@@ -508,6 +576,8 @@ ftcrfont_draw (struct glyph_string *s,
glyphs[i].index = s->char2b[from + i];
glyphs[i].x = x;
glyphs[i].y = y;
+ struct glyph_context *context = s->first_glyph->context;
+ glyphs[i].x -= (context->i * s->width);
x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font,
glyphs[i].index,
NULL));
diff --git a/src/hbfont.c b/src/hbfont.c
index 576c5fe7f6..5c3c690281 100644
--- a/src/hbfont.c
+++ b/src/hbfont.c
@@ -578,7 +578,7 @@ hbfont_shape (Lisp_Object lgstring, Lisp_Object direction)
LGLYPH_SET_CODE (lglyph, info[i].codepoint);
unsigned code = info[i].codepoint;
- font->driver->text_extents (font, &code, 1, &metrics);
+ font->driver->text_extents (font, &code, 1, &metrics, NULL);
LGLYPH_SET_WIDTH (lglyph, metrics.width);
LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
diff --git a/src/lisp.h b/src/lisp.h
index ad7d67ae69..c4ae954999 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1103,6 +1103,7 @@ DEFINE_GDB_SYMBOL_END (PSEUDOVECTOR_FLAG)
PVEC_MUTEX,
PVEC_CONDVAR,
PVEC_MODULE_FUNCTION,
+ PVEC_GLYPH_CONTEXT,
/* These should be last, for internal_equal and sxhash_obj. */
PVEC_COMPILED,
diff --git a/src/xdisp.c b/src/xdisp.c
index cf15f579b5..41a7b4235a 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -27499,14 +27499,15 @@ append_glyph_string (struct glyph_string **head, struct glyph_string **tail,
static struct face *
get_char_face_and_encoding (struct frame *f, int c, int face_id,
- unsigned *char2b, bool display_p)
+ unsigned *char2b, bool display_p,
+ struct glyph_context *context)
{
struct face *face = FACE_FROM_ID (f, face_id);
unsigned code = 0;
if (face->font)
{
- code = face->font->driver->encode_char (face->font, c);
+ code = face->font->driver->encode_char (face->font, c, context);
if (code == FONT_INVALID_CODE)
code = 0;
@@ -27533,7 +27534,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id,
static struct face *
get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
- unsigned *char2b)
+ unsigned *char2b, struct glyph_context *context)
{
struct face *face;
unsigned code = 0;
@@ -27549,7 +27550,8 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
if (CHAR_BYTE8_P (glyph->u.ch))
code = CHAR_TO_BYTE8 (glyph->u.ch);
else
- code = face->font->driver->encode_char (face->font, glyph->u.ch);
+ code = face->font->driver->encode_char (face->font, glyph->u.ch,
+ context);
if (code == FONT_INVALID_CODE)
code = 0;
@@ -27565,14 +27567,15 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
Return true iff FONT has a glyph for C. */
static bool
-get_char_glyph_code (int c, struct font *font, unsigned *char2b)
+get_char_glyph_code (int c, struct font *font, unsigned *char2b,
+ struct glyph_context *context)
{
unsigned code;
if (CHAR_BYTE8_P (c))
code = CHAR_TO_BYTE8 (c);
else
- code = font->driver->encode_char (font, c);
+ code = font->driver->encode_char (font, c, context);
if (code == FONT_INVALID_CODE)
return false;
@@ -27620,7 +27623,8 @@ fill_composite_glyph_string (struct glyph_string *s, struct face *base_face,
-1, Qnil);
face = get_char_face_and_encoding (s->f, c, face_id,
- s->char2b + i, true);
+ s->char2b + i, true,
+ NULL);
if (face)
{
if (! s->face)
@@ -27777,12 +27781,13 @@ fill_glyph_string (struct glyph_string *s, int face_id,
&& glyph->glyph_not_available_p == glyph_not_available_p)
{
s->face = get_glyph_face_and_encoding (s->f, glyph,
- s->char2b + s->nchars);
+ s->char2b + s->nchars,
+ glyph->context);
++s->nchars;
eassert (s->nchars <= end - start);
s->width += glyph->pixel_width;
- if (glyph++->padding_p != s->padding_p)
- break;
+ glyph++;
+ break;
}
s->font = s->face->font;
@@ -27877,7 +27882,8 @@ fill_stretch_glyph_string (struct glyph_string *s, int start, int end)
}
static struct font_metrics *
-get_per_char_metric (struct font *font, const unsigned *char2b)
+get_per_char_metric (struct font *font, const unsigned *char2b,
+ struct glyph_context *context)
{
static struct font_metrics metrics;
@@ -27886,7 +27892,7 @@ get_per_char_metric (struct font *font, const unsigned *char2b)
if (*char2b == FONT_INVALID_CODE)
return NULL;
- font->driver->text_extents (font, char2b, 1, &metrics);
+ font->driver->text_extents (font, char2b, 1, &metrics, context);
return &metrics;
}
@@ -27908,9 +27914,10 @@ normal_char_ascent_descent (struct font *font, int c, int *ascent, int *descent)
/* Get metrics of C, defaulting to a reasonably sized ASCII
character. */
- if (get_char_glyph_code (c >= 0 ? c : '{', font, &char2b))
+ if (get_char_glyph_code (c >= 0 ? c : '{', font, &char2b, NULL))
{
- struct font_metrics *pcm = get_per_char_metric (font, &char2b);
+ struct font_metrics *pcm = get_per_char_metric (font, &char2b,
+ NULL);
if (!(pcm->width == 0 && pcm->rbearing == 0 && pcm->lbearing == 0))
{
@@ -27952,10 +27959,12 @@ gui_get_glyph_overhangs (struct glyph *glyph, struct frame *f, int *left, int *r
if (glyph->type == CHAR_GLYPH)
{
unsigned char2b;
- struct face *face = get_glyph_face_and_encoding (f, glyph, &char2b);
+ struct face *face = get_glyph_face_and_encoding (f, glyph, &char2b,
+ NULL);
if (face->font)
{
- struct font_metrics *pcm = get_per_char_metric (face->font, &char2b);
+ struct font_metrics *pcm = get_per_char_metric (face->font, &char2b,
+ NULL);
if (pcm)
{
if (pcm->rbearing > pcm->width)
@@ -29841,12 +29850,12 @@ produce_glyphless_glyph (struct it *it, bool for_no_font, Lisp_Object acronym)
str = buf;
}
for (len = 0; str[len] && ASCII_CHAR_P (str[len]) && len < 6; len++)
- code[len] = font->driver->encode_char (font, str[len]);
+ code[len] = font->driver->encode_char (font, str[len], NULL);
upper_len = (len + 1) / 2;
font->driver->text_extents (font, code, upper_len,
- &metrics_upper);
+ &metrics_upper, NULL);
font->driver->text_extents (font, code + upper_len, len - upper_len,
- &metrics_lower);
+ &metrics_lower, NULL);
@@ -29936,6 +29945,40 @@ #define IT_APPLY_FACE_BOX(it, face) \
} \
} while (false)
+static struct glyph_context *
+make_context (struct it *it)
+{
+ struct glyph_context *context = xmalloc (sizeof *context); // XXX GC
+ char *string = xmalloc (128);
+ char *p = string;
+ ptrdiff_t bytepos = it->current.pos.bytepos;
+ ptrdiff_t charpos = it->current.pos.charpos;
+ ptrdiff_t bp5 = bytepos;
+ ptrdiff_t bp0 = bp5;
+ ptrdiff_t bp1 = bp5;
+ while (bytepos > BEG_BYTE && bp5 - bytepos < 32)
+ dec_both (&charpos, &bytepos);
+ bp0 = bytepos;
+ int i = 0;
+ Lisp_Object pos = make_fixnum (0);
+ while (bytepos >= BEG_BYTE && bytepos < Z_BYTE && bytepos - bp0 < 32)
+ {
+ inc_both (&charpos, &bytepos);
+ memcpy (p, BUF_BYTE_ADDRESS (current_buffer, bytepos - prev_char_len (bytepos)), prev_char_len (bytepos));
+ p += prev_char_len (bytepos);
+ ++i;
+ if (bytepos == bp5)
+ pos = make_fixnum (i);
+ }
+ bp1 = bytepos;
+ eassert (strlen (p) == bp1 - bp0);
+ *p++ = it->c;
+ *p++ = 0;
+ context->string = build_string (string);
+ context->position = pos;
+ return context;
+}
+
/* RIF:
Produce glyphs/get display metrics for the display element IT is
loaded with. See the description of struct it in dispextern.h
@@ -29973,6 +30016,7 @@ gui_produce_glyphs (struct it *it)
if (font->vertical_centering)
boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+ struct glyph_context *context = NULL;
if (it->char_to_display != '\n' && it->char_to_display != '\t')
{
it->nglyphs = 1;
@@ -29989,9 +30033,11 @@ gui_produce_glyphs (struct it *it)
it->descent = FONT_DESCENT (font) - boff;
}
- if (get_char_glyph_code (it->char_to_display, font, &char2b))
+ context = make_context (it);
+ if (get_char_glyph_code (it->char_to_display, font, &char2b,
+ context))
{
- pcm = get_per_char_metric (font, &char2b);
+ pcm = get_per_char_metric (font, &char2b, context);
if (pcm->width == 0
&& pcm->rbearing == 0 && pcm->lbearing == 0)
pcm = NULL;
@@ -30079,9 +30125,13 @@ gui_produce_glyphs (struct it *it)
/ FONT_HEIGHT (font));
append_stretch_glyph (it, it->object, it->pixel_width,
it->ascent + it->descent, ascent);
+ it->glyph_row->glyphs[it->area][it->glyph_row->used[it->area] - 1].context = NULL;
}
else
- append_glyph (it);
+ {
+ append_glyph (it);
+ it->glyph_row->glyphs[it->area][it->glyph_row->used[it->area] - 1].context = context;
+ }
/* If characters with lbearing or rbearing are displayed
in this line, record that fact in a flag of the
@@ -30233,9 +30283,9 @@ gui_produce_glyphs (struct it *it)
it->nglyphs = 1;
if (FONT_TOO_HIGH (font))
{
- if (get_char_glyph_code (' ', font, &char2b))
+ if (get_char_glyph_code (' ', font, &char2b, NULL))
{
- pcm = get_per_char_metric (font, &char2b);
+ pcm = get_per_char_metric (font, &char2b, NULL);
if (pcm->width == 0
&& pcm->rbearing == 0 && pcm->lbearing == 0)
pcm = NULL;
@@ -30372,8 +30422,8 @@ gui_produce_glyphs (struct it *it)
if (! font_not_found_p)
{
get_char_face_and_encoding (it->f, c, it->face_id,
- &char2b, false);
- pcm = get_per_char_metric (font, &char2b);
+ &char2b, false, NULL);
+ pcm = get_per_char_metric (font, &char2b, NULL);
}
/* Initialize the bounding box. */
@@ -30433,8 +30483,9 @@ gui_produce_glyphs (struct it *it)
else
{
get_char_face_and_encoding (it->f, ch, face_id,
- &char2b, false);
- pcm = get_per_char_metric (font, &char2b);
+ &char2b, false,
+ make_context (it));
+ pcm = get_per_char_metric (font, &char2b, make_context (it));
}
if (! pcm)
cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0;
diff --git a/src/xterm.c b/src/xterm.c
index 7989cecec7..3b5f0d3524 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -1703,7 +1703,8 @@ x_compute_glyph_string_overhangs (struct glyph_string *s)
if (s->first_glyph->type == CHAR_GLYPH)
{
struct font *font = s->font;
- font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
+ font->driver->text_extents (font, s->char2b, s->nchars, &metrics,
+ NULL);
}
else
{
@@ -2047,7 +2048,7 @@ x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
/* It is assured that all LEN characters in STR is ASCII. */
for (j = 0; j < len; j++)
- char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF;
+ char2b[j] = s->font->driver->encode_char (s->font, str[j], NULL) & 0xFFFF;
s->font->driver->draw (s, 0, upper_len,
x + glyph->slice.glyphless.upper_xoff,
s->ybase + glyph->slice.glyphless.upper_yoff,
^ permalink raw reply related [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-19 21:43 ` Pip Cet
@ 2020-05-20 1:41 ` Clément Pit-Claudel
2020-05-20 2:07 ` Ligatures Stefan Monnier
` (2 subsequent siblings)
3 siblings, 0 replies; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-20 1:41 UTC (permalink / raw)
To: Pip Cet; +Cc: Eli Zaretskii, Alan Third, emacs-devel
On 19/05/2020 17.43, Pip Cet wrote:
> And I'm afraid the difference is much more obvious with box cursors
> than it is with carets. I'm attaching a screenshot of a patched Emacs
> displaying "ffi", with point on the second f, in the "Linux Libertine
> Display O" font (using approximately equal slices).
Beauty is in the eye of the beholder :) This looks great to me, actually.
Maybe I'm just used to it because it's consistent with what Firefox does when I select text, and I have a habit of randomly selecting text while I read?
Thanks for working on this!
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-19 21:43 ` Pip Cet
2020-05-20 1:41 ` Clément Pit-Claudel
@ 2020-05-20 2:07 ` Stefan Monnier
2020-05-20 7:14 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) tomas
2020-05-20 15:18 ` Eli Zaretskii
3 siblings, 0 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-20 2:07 UTC (permalink / raw)
To: Pip Cet; +Cc: Clément Pit-Claudel, emacs-devel, Eli Zaretskii, Alan Third
> than it is with carets. I'm attaching a screenshot of a patched Emacs
> displaying "ffi", with point on the second f, in the "Linux Libertine
> Display O" font (using approximately equal slices).
This looks pretty good to me. Not perfect, but to the extent that the
border of the drawn cursor go right through the "space" that separates the
letters, it shows clearly where we are.
> I think this is a bit of a worst-case scenario
I hope you're right.
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-19 21:43 ` Pip Cet
2020-05-20 1:41 ` Clément Pit-Claudel
2020-05-20 2:07 ` Ligatures Stefan Monnier
@ 2020-05-20 7:14 ` tomas
2020-05-20 15:18 ` Eli Zaretskii
3 siblings, 0 replies; 145+ messages in thread
From: tomas @ 2020-05-20 7:14 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 591 bytes --]
On Tue, May 19, 2020 at 09:43:49PM +0000, Pip Cet wrote:
[...]
> And I'm afraid the difference is much more obvious with box cursors
> than it is with carets. I'm attaching a screenshot of a patched Emacs
> displaying "ffi", with point on the second f, in the "Linux Libertine
> Display O" font (using approximately equal slices).
Nice. I understand what miffs you (the overhang falls off the cursor
box, "compensated" by the wrong overhang entering from the left),
but given the information available you just can't do better.
IMHO it looks fine. Thanks for showing us :-)
Cheers
-- t
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-19 21:43 ` Pip Cet
` (2 preceding siblings ...)
2020-05-20 7:14 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) tomas
@ 2020-05-20 15:18 ` Eli Zaretskii
2020-05-20 17:31 ` Clément Pit-Claudel
2020-05-21 10:01 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Pip Cet
3 siblings, 2 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-20 15:18 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Tue, 19 May 2020 21:43:49 +0000
> Cc: Eli Zaretskii <eliz@gnu.org>, Alan Third <alan@idiocy.org>, emacs-devel@gnu.org
>
> And I'm afraid the difference is much more obvious with box cursors
> than it is with carets. I'm attaching a screenshot of a patched Emacs
> displaying "ffi", with point on the second f, in the "Linux Libertine
> Display O" font (using approximately equal slices).
>
> I think this is a bit of a worst-case scenario, a three-letter
> ligature in a font using ligatures and overhangs very
> enthusiastically. It might be okay for other fonts.
I'm not sure this is the worst case. It might be the worst case if we
are talking about ligatures that involve only ASCII characters, and
don't involve symbols like ==> that gets converted to ⇒. But in
general, there are worse cases, like á (two codepoints). And for
kicks see the Khmer hello in etc/HELLO, where you can find 4
codepoints that produce a grapheme cluster made of 3 glyphs.
If we only want this feature for ASCII ligatures, then it sounds like
a limitation to me (and frankly, somewhat unclean as features go), but
if we really want this only for these limited cases, we will need to
somehow indicate to the display engine which ligatures are to be
handled like this and which aren't.
> My remaining idea is to stretch characters so we can break up a
> ligature without changing its total width. I'm not sure how to do
> that, though.
I don't think I understand what you'd like to do. Can you elaborate?
> (I'm also attaching the patch, for the morbidly curious; it isn't
> clean, readable, or finished in any way, and contains at least one
> obvious bug. It's just good enough to produce the screenshot, and
> maybe it can serve as a hint as to which files need changing for
> ligatures to work; but such changes would have to be done very
> differently from the patch.).
Right, the actual implementation will have to be different. In
particular, I think that if ligatures will use automatic compositions,
the information you need is already stored in the composition table
and reachable from the glyph string, so you don't need to invoke the
shaper again.
I see you implemented this for static compositions, which are
semi-obsolete. Also, I don't see the code which moves point inside
the ligature; Emacs will not allow doing that by default. In
particular, how did you tell the display code to show the cursor on
the middle 'f', not on the first one? Did I miss something?
And finally, you said you intended to do this via row->clip, but this
patch does something very different. What changed your mind?
Thanks.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-20 15:18 ` Eli Zaretskii
@ 2020-05-20 17:31 ` Clément Pit-Claudel
2020-05-20 18:01 ` Eli Zaretskii
2020-05-20 23:19 ` Ligatures Stefan Monnier
2020-05-21 10:01 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Pip Cet
1 sibling, 2 replies; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-20 17:31 UTC (permalink / raw)
To: Eli Zaretskii, Pip Cet; +Cc: alan, emacs-devel
On 20/05/2020 11.18, Eli Zaretskii wrote:
> It might be the worst case if we are talking about ligatures that
> involve only ASCII characters, and don't involve symbols like ==>
> that gets converted to ⇒.
Wouldn't ==> be converted to ⟹ instead of ⇒? But regardless, what's the issue with ⇒?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-20 17:31 ` Clément Pit-Claudel
@ 2020-05-20 18:01 ` Eli Zaretskii
2020-05-20 18:33 ` Clément Pit-Claudel
2020-05-20 23:19 ` Ligatures Stefan Monnier
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-20 18:01 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Wed, 20 May 2020 13:31:13 -0400
>
> On 20/05/2020 11.18, Eli Zaretskii wrote:
> > It might be the worst case if we are talking about ligatures that
> > involve only ASCII characters, and don't involve symbols like ==>
> > that gets converted to ⇒.
>
> Wouldn't ==> be converted to ⟹ instead of ⇒?
Yes, to ⟹, sorry.
> But regardless, what's the issue with ⇒?
The issue with ⟹ is that the stem doesn't seem to be splittable into 2
parts, whereas "==" are two characters.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-20 18:01 ` Eli Zaretskii
@ 2020-05-20 18:33 ` Clément Pit-Claudel
2020-05-20 18:49 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-20 18:33 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 20/05/2020 14.01, Eli Zaretskii wrote:
>> But regardless, what's the issue with ⇒?
>
> The issue with ⟹ is that the stem doesn't seem to be splittable into 2
> parts, whereas "==" are two characters.
Oh, I see the worry, but I don't think it's a problem — it's a feature to split the stem into two parts :) In a monospace font, it should look obvious what's happening, since ⟹ will occupy three columns.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-20 18:33 ` Clément Pit-Claudel
@ 2020-05-20 18:49 ` Eli Zaretskii
2020-05-20 18:53 ` Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-20 18:49 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Wed, 20 May 2020 14:33:24 -0400
>
> On 20/05/2020 14.01, Eli Zaretskii wrote:
> >> But regardless, what's the issue with ⇒?
> >
> > The issue with ⟹ is that the stem doesn't seem to be splittable into 2
> > parts, whereas "==" are two characters.
>
> Oh, I see the worry, but I don't think it's a problem — it's a feature to split the stem into two parts :)
Then I guess we have very different views of what is a "feature". To
me, this looks like a terrible kludge.
> In a monospace font, it should look obvious what's happening, since ⟹ will occupy three columns.
Here it occupies only two.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-20 18:49 ` Eli Zaretskii
@ 2020-05-20 18:53 ` Clément Pit-Claudel
2020-05-20 19:02 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-20 18:53 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 20/05/2020 14.49, Eli Zaretskii wrote:
>> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Wed, 20 May 2020 14:33:24 -0400
>>
>> On 20/05/2020 14.01, Eli Zaretskii wrote:
>>>> But regardless, what's the issue with ⇒?
>>>
>>> The issue with ⟹ is that the stem doesn't seem to be splittable into 2
>>> parts, whereas "==" are two characters.
>>
>> Oh, I see the worry, but I don't think it's a problem — it's a feature to split the stem into two parts :)
>
> Then I guess we have very different views of what is a "feature". To
> me, this looks like a terrible kludge.
Yet, that's what everyone else is doing, so at least it's a predictable (and convenient) kludge.
>> In a monospace font, it should look obvious what's happening, since ⟹ will occupy three columns.
>
> Here it occupies only two.
Do you have a font with ligatures that composes ==> into ⟹, taking only two characters?
Most of the monospace fonts on my machine show ⇒ as one character and ⟹ as two — but the ones that have ligatures changing => into ⇒ and ==> into ⟹ all respect the widths of the characters they compose, so ⇒ is two characters wide and ⟹ is three characters wide.
I don't think the width of ⟹ as a non-composed character is too relevant, since we won't break it up, right?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-20 18:53 ` Clément Pit-Claudel
@ 2020-05-20 19:02 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-20 19:02 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Wed, 20 May 2020 14:53:59 -0400
>
> On 20/05/2020 14.49, Eli Zaretskii wrote:
> >> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> >> Date: Wed, 20 May 2020 14:33:24 -0400
> >>
> >> Oh, I see the worry, but I don't think it's a problem — it's a feature to split the stem into two parts :)
> >
> > Then I guess we have very different views of what is a "feature". To
> > me, this looks like a terrible kludge.
>
> Yet, that's what everyone else is doing, so at least it's a predictable (and convenient) kludge.
Since when we in Emacs do stuff "like everyone else" and feel good
about that?
Anyway, this argument about personal preferences is futile. Just
understand that a feature that works for some vaguely-defined use
cases, but doesn't work for the rest is a misfeature in my book.
> I don't think the width of ⟹ as a non-composed character is too relevant, since we won't break it up, right?
My point is that you cannot rely on the width being 3 columns. It may
or may not be so.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-20 17:31 ` Clément Pit-Claudel
2020-05-20 18:01 ` Eli Zaretskii
@ 2020-05-20 23:19 ` Stefan Monnier
1 sibling, 0 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-20 23:19 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: Eli Zaretskii, alan, Pip Cet, emacs-devel
>> It might be the worst case if we are talking about ligatures that
>> involve only ASCII characters, and don't involve symbols like ==>
>> that gets converted to ⇒.
> Wouldn't ==> be converted to ⟹ instead of ⇒? But regardless, what's the issue with ⇒?
Using `misc-fixed` here, those two above are displayed identically (as
single-column char) ;-)
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-20 15:18 ` Eli Zaretskii
2020-05-20 17:31 ` Clément Pit-Claudel
@ 2020-05-21 10:01 ` Pip Cet
2020-05-21 14:11 ` Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-21 10:01 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
Hi, Eli,
On Wed, May 20, 2020 at 3:31 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Tue, 19 May 2020 21:43:49 +0000
> > Cc: Eli Zaretskii <eliz@gnu.org>, Alan Third <alan@idiocy.org>, emacs-devel@gnu.org
> >
> > And I'm afraid the difference is much more obvious with box cursors
> > than it is with carets. I'm attaching a screenshot of a patched Emacs
> > displaying "ffi", with point on the second f, in the "Linux Libertine
> > Display O" font (using approximately equal slices).
> >
> > I think this is a bit of a worst-case scenario, a three-letter
> > ligature in a font using ligatures and overhangs very
> > enthusiastically. It might be okay for other fonts.
>
> I'm not sure this is the worst case. It might be the worst case if we
> are talking about ligatures that involve only ASCII characters, and
> don't involve symbols like ==> that gets converted to ⇒. But in
> general, there are worse cases, like á (two codepoints). And for
> kicks see the Khmer hello in etc/HELLO, where you can find 4
> codepoints that produce a grapheme cluster made of 3 glyphs.
You're correct: I'm simply not dealing with Khmer or composed
characters (which are different from ligatures, of course) in the
patch, and I'm not certain how to deal with them in theory, either.
> If we only want this feature for ASCII ligatures, then it sounds like
> a limitation to me (and frankly, somewhat unclean as features go),
Not "only for ASCII ligatures", but not "any conceivable combination
of codepoints into glyphs" either. Just those supported by the font
and Harfbuzz.
> but
> if we really want this only for these limited cases, we will need to
> somehow indicate to the display engine which ligatures are to be
> handled like this and which aren't.
Well, we now know that fonts can provide information about how a
ligature is to be split into one-dimensional slices; I filed a pull
request against Harfbuzz (since merged) that would actually make the
corresponding API work, at least for the "Libertinus" font family.
Of course that means that Emacs behavior would depend on the font
tables in ways it currently doesn't. That's a problem.
> > My remaining idea is to stretch characters so we can break up a
> > ligature without changing its total width. I'm not sure how to do
> > that, though.
>
> I don't think I understand what you'd like to do. Can you elaborate?
My idea was to display "ffi" with the point on the second f by
condensing an "f" glyph to cover the middle third of the "ffi" glyph.
However, I might have been too critical of how good the simple
solution deals with this case.
> > (I'm also attaching the patch, for the morbidly curious; it isn't
> > clean, readable, or finished in any way, and contains at least one
> > obvious bug. It's just good enough to produce the screenshot, and
> > maybe it can serve as a hint as to which files need changing for
> > ligatures to work; but such changes would have to be done very
> > differently from the patch.).
>
> Right, the actual implementation will have to be different. In
> particular, I think that if ligatures will use automatic compositions,
> the information you need is already stored in the composition table
> and reachable from the glyph string, so you don't need to invoke the
> shaper again.
Well, I'm sorry to bring up a different (though somewhat related
issue), but kerning is also an issue: we need a shaper to get that
right, not just a composition table, right?
> I see you implemented this for static compositions, which are
> semi-obsolete.
I'm sorry, I'm afraid I don't understand. This should handle any
composition the shaper does, and only those, but slices up everything
horizontally by default.
> Also, I don't see the code which moves point inside
> the ligature; Emacs will not allow doing that by default. In
> particular, how did you tell the display code to show the cursor on
> the middle 'f', not on the first one? Did I miss something?
I produce three "struct glyph"s for "ffi": each has width one third of
the actual font glyph, and stores, in convoluted form, information
about which slice of the font glyph is to be actually drawn.
> And finally, you said you intended to do this via row->clip, but this
> patch does something very different. What changed your mind?
I was surprised this no longer seemed to be strictly necessary: as far
as the display code is concerned, we're dealing with three separate
glyphs with overhang areas, and those are already handled by the
cursor-drawing code.
Clipping is still needed: to deal with double-drawing issues, and to
deal with such crimes as making part of a ligature have a different
foreground color.
I'm sorry it's not particularly obvious from the patch, but the
approach I took yesterday is this:
1. every struct glyph has a "context", which specifies the character
for the struct glyph and some surrounding text.
2. every struct glyph is converted to a slice of (currently) a single
font glyph, by sending the context through the shaper and cutting out
the relevant bits
3. struct glyphs are displayed one by one
Problems:
1. ligatures can cross line boundaries
2. the context has to be updated, and trigger redisplay of the struct glyph
3. clipping is necessary
4. there are N clipped drawing operations for a single glyph covering
N struct glyphs.
5. corner cases can have ambiguous context: for example, a string of
many "f"s would be paired into "ff" glyphs, and simply cutting off the
context after a certain number of characters might result in the wrong
pairing
On the other hand, it deals with kerning as well as ligatures. And
other problems (right now, we call the shaper on 64 characters for
every character we actually display, which makes things noticeably
slow) are fixable.
Overall, I'd like to think more about alternative approaches to the
"context string" one before implementing anything. How would that work
for kerning, in particular?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 10:01 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Pip Cet
@ 2020-05-21 14:11 ` Eli Zaretskii
2020-05-21 16:26 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-21 14:11 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Thu, 21 May 2020 10:01:03 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > If we only want this feature for ASCII ligatures, then it sounds like
> > a limitation to me (and frankly, somewhat unclean as features go),
>
> Not "only for ASCII ligatures", but not "any conceivable combination
> of codepoints into glyphs" either. Just those supported by the font
> and Harfbuzz.
>
> > but
> > if we really want this only for these limited cases, we will need to
> > somehow indicate to the display engine which ligatures are to be
> > handled like this and which aren't.
>
> Well, we now know that fonts can provide information about how a
> ligature is to be split into one-dimensional slices;
The question is: do we want to show those carets for all the character
compositions, even if the information is provided? If not, we will
have to indicate somehow whether they should or shouldn't be shown for
each particular grapheme cluster.
> Of course that means that Emacs behavior would depend on the font
> tables in ways it currently doesn't. That's a problem.
It isn't a problem to depend on that if most fonts provide this
information. Then we could simply say this is not supported when the
information is not in the font. But if many fonts that support
ligatures don't provide this information, we will need to have some
fallback, like assume that every codepoint has the same share of the
ligature's width. the fact that other applications use a simplistic
heuristic and not the information in the fonts suggests that either
the information is not readily available or there are some other
problems with using it.
> > Right, the actual implementation will have to be different. In
> > particular, I think that if ligatures will use automatic compositions,
> > the information you need is already stored in the composition table
> > and reachable from the glyph string, so you don't need to invoke the
> > shaper again.
>
> Well, I'm sorry to bring up a different (though somewhat related
> issue), but kerning is also an issue: we need a shaper to get that
> right, not just a composition table, right?
Automatic compositions already use the shaper, see autocmp_chars.
> > I see you implemented this for static compositions, which are
> > semi-obsolete.
>
> I'm sorry, I'm afraid I don't understand. This should handle any
> composition the shaper does, and only those, but slices up everything
> horizontally by default.
I'm talking about the changes in gui_produce_glyphs. Its high-level
structure is basically
if (it->what == IT_CHARACTER)
{
... /* handles character glyphs */
}
else if (it->what == IT_COMPOSITION && it->cmp_it.ch < 0)
{
... /* A static compositions. */
}
else if (it->what == IT_COMPOSITION)
{
/* A dynamic (automatic) composition. */
}
[...]
You made changes only in the "static compositions" part. That code
handles compositions created by compose-region. The "modern" way of
composing text in Emacs uses automatic compositions, which are
controlled by data in composition-function-table. This is where we
call the shaping engine to produce the glyphs according to rules
stored in the font. I don't see in your patch any changes that affect
ligatures created by automatic compositions; did I miss something?
If you use the automatic compositions route, then the information you
need, i.e. the number of clusters in the shaped text and the overall
width of the ligature, is already produced by the shaper and stored in
the "gstring" object in the composition table, see the description of
that object in the doc string of composition-get-gstring. So there
should be no need to invoke the shaper inside gui_produce_glyphs and
elsewhere. (If we want to use the carets information from the font,
we will probably need to extend the gstring object to store that as
well, and extend the shape method to extract this information when
available.)
> > Also, I don't see the code which moves point inside
> > the ligature; Emacs will not allow doing that by default. In
> > particular, how did you tell the display code to show the cursor on
> > the middle 'f', not on the first one? Did I miss something?
>
> I produce three "struct glyph"s for "ffi": each has width one third of
> the actual font glyph, and stores, in convoluted form, information
> about which slice of the font glyph is to be actually drawn.
Ah, okay, I missed that. But producing 3 glyphs instead of just one
is not necessarily the best idea, I think. As you point out, one
problem will be with splitting the ligature across lines. Another
problem is more expensive display. And we won't be able to display
the ligature as a single glyph, for those who want that, at least not
easily.
> > And finally, you said you intended to do this via row->clip, but this
> > patch does something very different. What changed your mind?
>
> I was surprised this no longer seemed to be strictly necessary: as far
> as the display code is concerned, we're dealing with three separate
> glyphs with overhang areas, and those are already handled by the
> cursor-drawing code.
Yes. But if we return to a single glyph, then we'd need to do some
clipping.
> On the other hand, it deals with kerning as well as ligatures.
You mean, kerning of simple characters, for which we don't produce
ligatures? Or kerning within ligatures? If the latter, then I don't
see why we'd need that: font designers already design the ligatures to
have the optimal kerning, no?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 14:11 ` Eli Zaretskii
@ 2020-05-21 16:26 ` Pip Cet
2020-05-21 19:08 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-21 16:26 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Thu, May 21, 2020 at 2:11 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Thu, 21 May 2020 10:01:03 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> > > but
> > > if we really want this only for these limited cases, we will need to
> > > somehow indicate to the display engine which ligatures are to be
> > > handled like this and which aren't.
> >
> > Well, we now know that fonts can provide information about how a
> > ligature is to be split into one-dimensional slices;
>
> The question is: do we want to show those carets for all the character
> compositions, even if the information is provided? If not, we will
> have to indicate somehow whether they should or shouldn't be shown for
> each particular grapheme cluster.
Oh. I hadn't thought about fonts providing such caret information in
cases where they shouldn't, but of course that's a valid concern.
> > Of course that means that Emacs behavior would depend on the font
> > tables in ways it currently doesn't. That's a problem.
>
> It isn't a problem to depend on that if most fonts provide this
> information.
> Then we could simply say this is not supported when the
> information is not in the font.
I'm not sure how simple that would be: we could treat ligatures
without carets as atomic, or we could tell harfbuzz not to apply
ligatures without carets, or maybe make that decision depend on
whether the ligature is required or discretionary...
> But if many fonts that support
> ligatures don't provide this information, we will need to have some
> fallback, like assume that every codepoint has the same share of the
> ligature's width. the fact that other applications use a simplistic
> heuristic and not the information in the fonts suggests that either
> the information is not readily available or there are some other
> problems with using it.
Correct, it does. I'm not sure which one is the case.
> > > Right, the actual implementation will have to be different. In
> > > particular, I think that if ligatures will use automatic compositions,
> > > the information you need is already stored in the composition table
> > > and reachable from the glyph string, so you don't need to invoke the
> > > shaper again.
> >
> > Well, I'm sorry to bring up a different (though somewhat related
> > issue), but kerning is also an issue: we need a shaper to get that
> > right, not just a composition table, right?
>
> Automatic compositions already use the shaper, see autocmp_chars.
I'm not sure I understand how kerning would work using automatic compositions.
> > > I see you implemented this for static compositions, which are
> > > semi-obsolete.
> >
> > I'm sorry, I'm afraid I don't understand. This should handle any
> > composition the shaper does, and only those, but slices up everything
> > horizontally by default.
>
> I'm talking about the changes in gui_produce_glyphs. Its high-level
> structure is basically
>
> if (it->what == IT_CHARACTER)
> {
> ... /* handles character glyphs */
> }
> else if (it->what == IT_COMPOSITION && it->cmp_it.ch < 0)
> {
> ... /* A static compositions. */
> }
> else if (it->what == IT_COMPOSITION)
> {
> /* A dynamic (automatic) composition. */
> }
> [...]
>
> You made changes only in the "static compositions" part.
No. I didn't touch the "static compositions" part at all, except for
passing an extra NULL pointer to an API I'd extended. (At least,
that's what I intended, for all the changes to be in the IT_CHARACTER
part).
> That code
> handles compositions created by compose-region. The "modern" way of
> composing text in Emacs uses automatic compositions, which are
> controlled by data in composition-function-table. This is where we
> call the shaping engine to produce the glyphs according to rules
> stored in the font. I don't see in your patch any changes that affect
> ligatures created by automatic compositions; did I miss something?
I don't think so; I went for a third route, that of leaving all
compositions handling to the shaper and doing none of it in Emacs
itself.
> If you use the automatic compositions route, then the information you
> need, i.e. the number of clusters in the shaped text and the overall
> width of the ligature, is already produced by the shaper and stored in
> the "gstring" object in the composition table, see the description of
> that object in the doc string of composition-get-gstring. So there
> should be no need to invoke the shaper inside gui_produce_glyphs and
> elsewhere. (If we want to use the carets information from the font,
> we will probably need to extend the gstring object to store that as
> well, and extend the shape method to extract this information when
> available.)
Yes, and that seemed too complicated for me for something that I
thought wouldn't handle kerning anyway...
> > > Also, I don't see the code which moves point inside
> > > the ligature; Emacs will not allow doing that by default. In
> > > particular, how did you tell the display code to show the cursor on
> > > the middle 'f', not on the first one? Did I miss something?
> >
> > I produce three "struct glyph"s for "ffi": each has width one third of
> > the actual font glyph, and stores, in convoluted form, information
> > about which slice of the font glyph is to be actually drawn.
>
> Ah, okay, I missed that. But producing 3 glyphs instead of just one
> is not necessarily the best idea, I think.
I agree! I'd be happy to hear better ideas, and I think for now "use
fixed-width fonts" is a better idea...
> As you point out, one
> problem will be with splitting the ligature across lines. Another
> problem is more expensive display.
You mean the actual "copy the glyph bitmap to the glass" display?
Because I don't think that's relevant. Overall redisplay() time really
goes up calling the shaper on 32 characters for every character
displayed, though, so that's a concern I agree with.
> And we won't be able to display
> the ligature as a single glyph, for those who want that, at least not
> easily.
But that's what they can do now, with the IT_COMPOSITION case, right?
Because I did not touch that code so I didn't expect that to break
(famous last words).
> > > And finally, you said you intended to do this via row->clip, but this
> > > patch does something very different. What changed your mind?
> >
> > I was surprised this no longer seemed to be strictly necessary: as far
> > as the display code is concerned, we're dealing with three separate
> > glyphs with overhang areas, and those are already handled by the
> > cursor-drawing code.
>
> Yes. But if we return to a single glyph, then we'd need to do some
> clipping.
As I said, we need to do the clipping to render antialiased pixels properly.
It's just two lines of code in ftcrfont_draw:
cairo_rectangle (cr, x, y - FONT_BASE (face->font),
s->width, FONT_HEIGHT (face->font));
cairo_clip (cr);
> > On the other hand, it deals with kerning as well as ligatures.
>
> You mean, kerning of simple characters, for which we don't produce
> ligatures?
Yes, that's what I mean.
> Or kerning within ligatures? If the latter, then I don't
> see why we'd need that: font designers already design the ligatures to
> have the optimal kerning, no?
It's certainly not our job to fix that if they don't!
Perhaps I can digress a little and describe what I think the
interaction with the shaper should be like:
Emacs: I'd like to display codepoint 'f'
Harfbuzz: you'll have to tell me the codepoint before that
Emacs: 'f'
Harfbuzz: and the one after those two
Emacs: 'i'
Harfbuzz: and the one before all of those
Emacs: That's too expensive for me to compute / it's the beginning of
paragraph / a bidi boundary / an object without an assigned codepoint
/ ...
Harfbuzz: okay, display it as the middle slice of the "ffi" glyph
I.e., I'd like Harfbuzz to be asynchronous, and request more
information, parsimoniously, about the context of the codepoint we're
describing, rather than working in one go from "complete" information
to an indefinitely-long line of glyphs. And deal well with us deciding
it's too expensive to perform that much look-back/look-ahead. (Because
in real life, ligatures depend on knowing some amount of the context,
but not all of it, or people could never start writing.)
Of course, all this doesn't change that the "struct it" design is
somewhat difficult to extend to handling look-ahead: it's easy enough
to create a copy of the iterator and advance that while leaving the
actual iterator intact, but it's also really slow. In fact I suspect
the best way would be to make struct it a heap-allocated pseudovector
(not necessarily one ordinarily garbage-collected, though), and cache
"future" iterator states once we compute them.
You're correct when you say that some major redesign is needed in this
area, but I don't think that's the subject of the current discussion.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 16:26 ` Pip Cet
@ 2020-05-21 19:08 ` Eli Zaretskii
2020-05-21 20:51 ` Clément Pit-Claudel
2020-05-21 21:06 ` Pip Cet
0 siblings, 2 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-21 19:08 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Thu, 21 May 2020 16:26:13 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> On Thu, May 21, 2020 at 2:11 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > > From: Pip Cet <pipcet@gmail.com>
> > > Date: Thu, 21 May 2020 10:01:03 +0000
> > > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> > > > but
> > > > if we really want this only for these limited cases, we will need to
> > > > somehow indicate to the display engine which ligatures are to be
> > > > handled like this and which aren't.
> > >
> > > Well, we now know that fonts can provide information about how a
> > > ligature is to be split into one-dimensional slices;
> >
> > The question is: do we want to show those carets for all the character
> > compositions, even if the information is provided? If not, we will
> > have to indicate somehow whether they should or shouldn't be shown for
> > each particular grapheme cluster.
>
> Oh. I hadn't thought about fonts providing such caret information in
> cases where they shouldn't, but of course that's a valid concern.
>
> > > Of course that means that Emacs behavior would depend on the font
> > > tables in ways it currently doesn't. That's a problem.
> >
> > It isn't a problem to depend on that if most fonts provide this
> > information.
>
> > Then we could simply say this is not supported when the
> > information is not in the font.
>
> I'm not sure how simple that would be: we could treat ligatures
> without carets as atomic, or we could tell harfbuzz not to apply
> ligatures without carets, or maybe make that decision depend on
> whether the ligature is required or discretionary...
>
> > But if many fonts that support
> > ligatures don't provide this information, we will need to have some
> > fallback, like assume that every codepoint has the same share of the
> > ligature's width. the fact that other applications use a simplistic
> > heuristic and not the information in the fonts suggests that either
> > the information is not readily available or there are some other
> > problems with using it.
>
> Correct, it does. I'm not sure which one is the case.
>
> > > > Right, the actual implementation will have to be different. In
> > > > particular, I think that if ligatures will use automatic compositions,
> > > > the information you need is already stored in the composition table
> > > > and reachable from the glyph string, so you don't need to invoke the
> > > > shaper again.
> > >
> > > Well, I'm sorry to bring up a different (though somewhat related
> > > issue), but kerning is also an issue: we need a shaper to get that
> > > right, not just a composition table, right?
> >
> > Automatic compositions already use the shaper, see autocmp_chars.
>
> I'm not sure I understand how kerning would work using automatic compositions.
>
> > > > I see you implemented this for static compositions, which are
> > > > semi-obsolete.
> > >
> > > I'm sorry, I'm afraid I don't understand. This should handle any
> > > composition the shaper does, and only those, but slices up everything
> > > horizontally by default.
> >
> > I'm talking about the changes in gui_produce_glyphs. Its high-level
> > structure is basically
> >
> > if (it->what == IT_CHARACTER)
> > {
> > ... /* handles character glyphs */
> > }
> > else if (it->what == IT_COMPOSITION && it->cmp_it.ch < 0)
> > {
> > ... /* A static compositions. */
> > }
> > else if (it->what == IT_COMPOSITION)
> > {
> > /* A dynamic (automatic) composition. */
> > }
> > [...]
> >
> > You made changes only in the "static compositions" part.
>
> No. I didn't touch the "static compositions" part at all, except for
> passing an extra NULL pointer to an API I'd extended. (At least,
> that's what I intended, for all the changes to be in the IT_CHARACTER
> part).
I mean this part:
@@ -30433,8 +30483,9 @@ gui_produce_glyphs (struct it *it)
else
{
get_char_face_and_encoding (it->f, ch, face_id,
- &char2b, false);
- pcm = get_per_char_metric (font, &char2b);
+ &char2b, false,
+ make_context (it));
+ pcm = get_per_char_metric (font, &char2b, make_context (it));
}
This calls make_context and passes it to these functions. This code
handles static compositions only.
> > The "modern" way of composing text in Emacs uses automatic
> > compositions, which are controlled by data in
> > composition-function-table. This is where we call the shaping
> > engine to produce the glyphs according to rules stored in the
> > font. I don't see in your patch any changes that affect ligatures
> > created by automatic compositions; did I miss something?
>
> I don't think so; I went for a third route, that of leaving all
> compositions handling to the shaper and doing none of it in Emacs
> itself.
But automatic compositions do work by calling the shaper.
> Perhaps I can digress a little and describe what I think the
> interaction with the shaper should be like:
>
> Emacs: I'd like to display codepoint 'f'
> Harfbuzz: you'll have to tell me the codepoint before that
> Emacs: 'f'
> Harfbuzz: and the one after those two
> Emacs: 'i'
> Harfbuzz: and the one before all of those
> Emacs: That's too expensive for me to compute / it's the beginning of
> paragraph / a bidi boundary / an object without an assigned codepoint
> / ...
> Harfbuzz: okay, display it as the middle slice of the "ffi" glyph
>
> I.e., I'd like Harfbuzz to be asynchronous, and request more
> information, parsimoniously, about the context of the codepoint we're
> describing, rather than working in one go from "complete" information
> to an indefinitely-long line of glyphs. And deal well with us deciding
> it's too expensive to perform that much look-back/look-ahead. (Because
> in real life, ligatures depend on knowing some amount of the context,
> but not all of it, or people could never start writing.)
That would prevent Emacs from controlling what is and what isn't
composed, leaving the shaper in charge. We currently allow Lisp to
control that via composition-function-table, which provides a regexp
that text around a character must match in order for the matching
substring to be passed to the shaper. We never call the shaper unless
composition-function-table tells us to do so.
I'm not sure I understand what problems do you see with this design.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 19:08 ` Eli Zaretskii
@ 2020-05-21 20:51 ` Clément Pit-Claudel
2020-05-21 21:16 ` Pip Cet
2020-05-22 11:44 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
2020-05-21 21:06 ` Pip Cet
1 sibling, 2 replies; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-21 20:51 UTC (permalink / raw)
To: Eli Zaretskii, Pip Cet; +Cc: alan, emacs-devel
On 21/05/2020 15.08, Eli Zaretskii wrote:
> That would prevent Emacs from controlling what is and what isn't
> composed, leaving the shaper in charge. We currently allow Lisp to
> control that via composition-function-table, which provides a regexp
> that text around a character must match in order for the matching
> substring to be passed to the shaper. We never call the shaper unless
> composition-function-table tells us to do so.
Does this mean that for each font we need to re-encode the font's logic for deciding whether to use a ligature?
Some concrete examples: in Iosevka (*, (**, (***, (**** etc are all displayed with the * character vertically centered relative to the (, but a lone * is not centered. In Fira Code, punctuation is context-aware, so the "+" in "A + B" is not the same as the "+" in "a + b". In both of these faces, arrows can be of any length, and in Fira Code you can even mix and match them (see https://raw.githubusercontent.com/tonsky/FiraCode/master/extras/arrows.png).
The documentation of Fira Code does recommend composition-function-table here: https://github.com/tonsky/FiraCode/wiki/Emacs-instructions, but it seems like a lot of extra work for each font, isn't it?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 19:08 ` Eli Zaretskii
2020-05-21 20:51 ` Clément Pit-Claudel
@ 2020-05-21 21:06 ` Pip Cet
2020-05-22 6:06 ` Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-21 21:06 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Thu, May 21, 2020 at 7:08 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Thu, 21 May 2020 16:26:13 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > On Thu, May 21, 2020 at 2:11 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > No. I didn't touch the "static compositions" part at all, except for
> > passing an extra NULL pointer to an API I'd extended. (At least,
> > that's what I intended, for all the changes to be in the IT_CHARACTER
> > part).
>
> I mean this part:
>
> @@ -30433,8 +30483,9 @@ gui_produce_glyphs (struct it *it)
> else
> {
> get_char_face_and_encoding (it->f, ch, face_id,
> - &char2b, false);
> - pcm = get_per_char_metric (font, &char2b);
> + &char2b, false,
> + make_context (it));
> + pcm = get_per_char_metric (font, &char2b, make_context (it));
> }
>
> This calls make_context and passes it to these functions. This code
> handles static compositions only.
Oops, sorry. You're right, that change was harmless but unintended;
the relevant change is
@@ -29989,9 +30033,11 @@ gui_produce_glyphs (struct it *it)
it->descent = FONT_DESCENT (font) - boff;
}
- if (get_char_glyph_code (it->char_to_display, font, &char2b))
+ context = make_context (it);
+ if (get_char_glyph_code (it->char_to_display, font, &char2b,
+ context))
{
- pcm = get_per_char_metric (font, &char2b);
+ pcm = get_per_char_metric (font, &char2b, context);
if (pcm->width == 0
&& pcm->rbearing == 0 && pcm->lbearing == 0)
pcm = NULL;
> > > The "modern" way of composing text in Emacs uses automatic
> > > compositions, which are controlled by data in
> > > composition-function-table. This is where we call the shaping
> > > engine to produce the glyphs according to rules stored in the
> > > font. I don't see in your patch any changes that affect ligatures
> > > created by automatic compositions; did I miss something?
> >
> > I don't think so; I went for a third route, that of leaving all
> > compositions handling to the shaper and doing none of it in Emacs
> > itself.
>
> But automatic compositions do work by calling the shaper.
Yes, that observation is correct. What I'm doing is still very
different from the (semi-)automatic compositions composite.c does.
> > Perhaps I can digress a little and describe what I think the
> > interaction with the shaper should be like:
> >
> > Emacs: I'd like to display codepoint 'f'
> > Harfbuzz: you'll have to tell me the codepoint before that
> > Emacs: 'f'
> > Harfbuzz: and the one after those two
> > Emacs: 'i'
> > Harfbuzz: and the one before all of those
> > Emacs: That's too expensive for me to compute / it's the beginning of
> > paragraph / a bidi boundary / an object without an assigned codepoint
> > / ...
> > Harfbuzz: okay, display it as the middle slice of the "ffi" glyph
> >
> > I.e., I'd like Harfbuzz to be asynchronous, and request more
> > information, parsimoniously, about the context of the codepoint we're
> > describing, rather than working in one go from "complete" information
> > to an indefinitely-long line of glyphs. And deal well with us deciding
> > it's too expensive to perform that much look-back/look-ahead. (Because
> > in real life, ligatures depend on knowing some amount of the context,
> > but not all of it, or people could never start writing.)
>
> That would prevent Emacs from controlling what is and what isn't
> composed, leaving the shaper in charge.
Well, yes and no: the shaper is in charge, and I see absolutely
nothing wrong with that. You can tell the shaper not to perform
ligatures (or perform only some of them), or kerning, if you want to.
> We currently allow Lisp to
> control that via composition-function-table, which provides a regexp
> that text around a character must match in order for the matching
> substring to be passed to the shaper.
And you're suggesting that regexp be set to, say, ".+"? Because that's
the only way I've found of getting it to do kerning.
> We never call the shaper unless
> composition-function-table tells us to do so.
...whereas I want to call it every time, which is why having
composition-function-table in the loop seemed wasteful.
> I'm not sure I understand what problems do you see with this design.
I meant the redisplay engine in general, not the way automatic
compositions work.
(That's not to say I'm happy with automatic compositions, but that's a
different subject).
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 20:51 ` Clément Pit-Claudel
@ 2020-05-21 21:16 ` Pip Cet
2020-05-22 6:12 ` Eli Zaretskii
2020-05-22 11:44 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-21 21:16 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: Eli Zaretskii, alan, emacs-devel
On Thu, May 21, 2020 at 8:51 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:
> On 21/05/2020 15.08, Eli Zaretskii wrote:
> > That would prevent Emacs from controlling what is and what isn't
> > composed, leaving the shaper in charge. We currently allow Lisp to
> > control that via composition-function-table, which provides a regexp
> > that text around a character must match in order for the matching
> > substring to be passed to the shaper. We never call the shaper unless
> > composition-function-table tells us to do so.
>
> Does this mean that for each font we need to re-encode the font's logic for deciding whether to use a ligature?
I think
(set-char-table-range composition-function-table t '([".+" 0
font-shape-gstring]))
should work, but it has weird side effects that I'm pretty sure aren't
intended (paren highlighting is broken, for example).
Is that supposed to happen?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 21:06 ` Pip Cet
@ 2020-05-22 6:06 ` Eli Zaretskii
2020-05-22 9:34 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 6:06 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Thu, 21 May 2020 21:06:27 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > But automatic compositions do work by calling the shaper.
>
> Yes, that observation is correct. What I'm doing is still very
> different from the (semi-)automatic compositions composite.c does.
For ligatures, I don't think I understand why the automatic
compositions are not the way to go.
> > That would prevent Emacs from controlling what is and what isn't
> > composed, leaving the shaper in charge.
>
> Well, yes and no: the shaper is in charge, and I see absolutely
> nothing wrong with that. You can tell the shaper not to perform
> ligatures (or perform only some of them), or kerning, if you want to.
Tell it how? by introducing new Lisp options and data structures?
What would those new data structures be, and how will they be
different from composition-function-table?
> > We currently allow Lisp to
> > control that via composition-function-table, which provides a regexp
> > that text around a character must match in order for the matching
> > substring to be passed to the shaper.
>
> And you're suggesting that regexp be set to, say, ".+"? Because that's
> the only way I've found of getting it to do kerning.
I'm not talking about the kerning. This discussion is about
ligatures, AFAIU. For ligatures, the regexp should catch the
sequences of characters that should be ligated. ".+" is definitely
not right for ligatures, since it will significantly slow down
redisplay for no good reason.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 21:16 ` Pip Cet
@ 2020-05-22 6:12 ` Eli Zaretskii
2020-05-22 9:25 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 6:12 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Thu, 21 May 2020 21:16:44 +0000
> Cc: Eli Zaretskii <eliz@gnu.org>, alan@idiocy.org, emacs-devel@gnu.org
>
> (set-char-table-range composition-function-table t '([".+" 0
> font-shape-gstring]))
>
> should work, but it has weird side effects that I'm pretty sure aren't
> intended (paren highlighting is broken, for example).
This is not the right way. The right way is to do the likes of the
following:
(set-char-table-range
composition-function-table '(?f . ?f)
(list (vector "ffi" 0 'compose-gstring-for-graphic)))
This shows how to do this only for the "ffi" ligature, but I think it
makes the idea clear. Tassilo posted here some code ho wrote that
supports more (and different) ligatures which are supposed to be used
like prettify-symbols-mode. The idea is to populate
composition-function-table only for characters that should trigger
ligation.
Whether to use compose-gstring-for-graphic or font-shape-gstring
depends on what you want to happen when the font doesn't have a glyph
for a certain ligature: the latter will then cause the characters be
displayed as usual, as separate characters, the latter will display
them as a single display element, a kind of "fake ligature".
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 6:12 ` Eli Zaretskii
@ 2020-05-22 9:25 ` Pip Cet
2020-05-22 11:23 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-22 9:25 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Fri, May 22, 2020 at 6:12 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Thu, 21 May 2020 21:16:44 +0000
> > Cc: Eli Zaretskii <eliz@gnu.org>, alan@idiocy.org, emacs-devel@gnu.org
> >
> > (set-char-table-range composition-function-table t '([".+" 0
> > font-shape-gstring]))
> >
> > should work, but it has weird side effects that I'm pretty sure aren't
> > intended (paren highlighting is broken, for example).
>
> This is not the right way.
What is the right way, then? I want all ligatures my font supports.
Also, even if it is the wrong thing to do, why does it break seemingly
unrelated things?
> The right way is to do the likes of the
> following:
>
> (set-char-table-range
> composition-function-table '(?f . ?f)
> (list (vector "ffi" 0 'compose-gstring-for-graphic)))
> This shows how to do this only for the "ffi" ligature, but I think it
> makes the idea clear.
I'm afraid it doesn't, to me.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 6:06 ` Eli Zaretskii
@ 2020-05-22 9:34 ` Pip Cet
2020-05-22 11:33 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-22 9:34 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Fri, May 22, 2020 at 6:06 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Thu, 21 May 2020 21:06:27 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > > But automatic compositions do work by calling the shaper.
> >
> > Yes, that observation is correct. What I'm doing is still very
> > different from the (semi-)automatic compositions composite.c does.
>
> For ligatures, I don't think I understand why the automatic
> compositions are not the way to go.
I don't think I've concluded they're not, though I'm strongly leaning
that way. I didn't use them in the first patch, but that's probably
easy enough to change.
(Playing around with composite.c, I noticed it's very easy to get into
an unquittable infinite loop by specifying invalid values in
composition-function-table. That should probably be fixed).
> > > That would prevent Emacs from controlling what is and what isn't
> > > composed, leaving the shaper in charge.
> >
> > Well, yes and no: the shaper is in charge, and I see absolutely
> > nothing wrong with that. You can tell the shaper not to perform
> > ligatures (or perform only some of them), or kerning, if you want to.
>
> Tell it how? by introducing new Lisp options and data structures?
Yes. A buffer option to disable ligatures/kerning would probably
suffice, because it would essentially only be used to work around
buggy fonts.
> What would those new data structures be, and how will they be
> different from composition-function-table?
> > > We currently allow Lisp to
> > > control that via composition-function-table, which provides a regexp
> > > that text around a character must match in order for the matching
> > > substring to be passed to the shaper.
> >
> > And you're suggesting that regexp be set to, say, ".+"? Because that's
> > the only way I've found of getting it to do kerning.
>
> I'm not talking about the kerning. This discussion is about
> ligatures, AFAIU.
Oh. I understood it differently, because kerning is an important
problem to solve in order to use variable-pitch fonts for English
text.
> For ligatures, the regexp should catch the
> sequences of characters that should be ligated.
I have to know that before using auto-composition-mode? How do I work
it out? Do I have to disassemble the font and reimplement the relevant
tables?
> ".+" is definitely
> not right for ligatures, since it will significantly slow down
> redisplay
So that's another argument against auto-composition-mode: it's too
slow unless you know in advance which ligatures you want. Right?
> for no good reason.
I think "because I want the ligatures the font provides, and I don't
care to work out in advance which ones those are" is a pretty good
reason.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 9:25 ` Pip Cet
@ 2020-05-22 11:23 ` Eli Zaretskii
2020-05-22 12:52 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 11:23 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Fri, 22 May 2020 09:25:31 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > > should work, but it has weird side effects that I'm pretty sure aren't
> > > intended (paren highlighting is broken, for example).
> >
> > This is not the right way.
>
> What is the right way, then? I want all ligatures my font supports.
You can request all the ligatures that _can_ be supported; those which
aren't available in the font you use will not be ligated (if you use
font-shape-gstring in the composition-function-table slot).
Or you can request only those ligatures that make sense for the
particular use case. For example, when displaying program source code
you'd probably want the various symbols, like -> etc., to produce
ligatures, but you most probably won't want "ffi" in a variable name
to produce a ligature.
Or you can provide your own function to use in the
composition-function-table, and that function can do more complex
stuff, like refuse to ligate under some complicated conditions.
Therefore, I think letting Lisp programs (and thus users) control what
gets composed into ligatures and what doesn't is an important feature
to have. We should develop it more, because currently it lacks some
features we'd need for better ligature support (see the TODO item
about that), but I think the basic design is valid. At least I didn't
yet see any evidence that it isn't valid; perhaps when we develop it
more and/or start using it more, we will find some problems, but I
don't see them yet.
> Also, even if it is the wrong thing to do, why does it break seemingly
> unrelated things?
I don't know. Can you show how to reproduce that in the current
codebase on master? Then I'll look into it.
> > (set-char-table-range
> > composition-function-table '(?f . ?f)
> > (list (vector "ffi" 0 'compose-gstring-for-graphic)))
>
> > This shows how to do this only for the "ffi" ligature, but I think it
> > makes the idea clear.
>
> I'm afraid it doesn't, to me.
Doesn't make the idea clear or doesn't produce the ligature? If the
latter, then I'm puzzled, because it did work for me with a font that
has the ffi ligature. If the former, please ask more questions and I
will try to explain as best I can.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 9:34 ` Pip Cet
@ 2020-05-22 11:33 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 11:33 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Fri, 22 May 2020 09:34:54 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > > Well, yes and no: the shaper is in charge, and I see absolutely
> > > nothing wrong with that. You can tell the shaper not to perform
> > > ligatures (or perform only some of them), or kerning, if you want to.
> >
> > Tell it how? by introducing new Lisp options and data structures?
>
> Yes. A buffer option to disable ligatures/kerning would probably
> suffice, because it would essentially only be used to work around
> buggy fonts.
That option already exists: disable auto-composition-mode in a buffer
where you don't want that.
If you want to disable only some compositions, like only ligatures, or
only some of the ligatures, you can do that in two ways:
. modify composition-function-table (although this currently cannot
be done only for a single buffer, I think: something to fix for
better ligature support)
. provide your own composition function to be used in
composition-function-table, which could then be programmed to
decide which ligatures to allow and which not to allow
> > I'm not talking about the kerning. This discussion is about
> > ligatures, AFAIU.
>
> Oh. I understood it differently, because kerning is an important
> problem to solve in order to use variable-pitch fonts for English
> text.
Perhaps so, but let's discuss the kerning issue separately. It's a
separate problem, AFAIU.
> > For ligatures, the regexp should catch the
> > sequences of characters that should be ligated.
>
> I have to know that before using auto-composition-mode? How do I work
> it out?
I tried to answer this in my previous message in this thread.
> > ".+" is definitely
> > not right for ligatures, since it will significantly slow down
> > redisplay
>
> So that's another argument against auto-composition-mode: it's too
> slow unless you know in advance which ligatures you want. Right?
It's too slow if we have too many ligatures, or, more generally, too
many characters to compose. Character composition works by calling
Lisp (so as to allow use the flexibility we need, see the other
messages), and calling Lisp for too many characters during redisplay
will make redisplay slower. This is one reason why we don't run every
buffer substring through the shaper, although the HarfBuzz developers
told me long ago they thought this was a flaw in our design.
> > for no good reason.
>
> I think "because I want the ligatures the font provides, and I don't
> care to work out in advance which ones those are" is a pretty good
> reason.
Let's see if I succeeded to convince you that we have better
solutions.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-21 20:51 ` Clément Pit-Claudel
2020-05-21 21:16 ` Pip Cet
@ 2020-05-22 11:44 ` Eli Zaretskii
2020-05-22 13:26 ` Clément Pit-Claudel
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 11:44 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Thu, 21 May 2020 16:51:47 -0400
>
> On 21/05/2020 15.08, Eli Zaretskii wrote:
> > That would prevent Emacs from controlling what is and what isn't
> > composed, leaving the shaper in charge. We currently allow Lisp to
> > control that via composition-function-table, which provides a regexp
> > that text around a character must match in order for the matching
> > substring to be passed to the shaper. We never call the shaper unless
> > composition-function-table tells us to do so.
>
> Does this mean that for each font we need to re-encode the font's logic for deciding whether to use a ligature?
I don't think so, but I'm not yet sure I understand all the details of
the use cases you have in mind. See also my responses to Pip Cet:
perhaps they answer also your questions here.
> Some concrete examples: in Iosevka (*, (**, (***, (**** etc are all displayed with the * character vertically centered relative to the (, but a lone * is not centered. In Fira Code, punctuation is context-aware, so the "+" in "A + B" is not the same as the "+" in "a + b". In both of these faces, arrows can be of any length, and in Fira Code you can even mix and match them (see https://raw.githubusercontent.com/tonsky/FiraCode/master/extras/arrows.png).
How do you solve this in prettify-symbols-mode?
In general, I envision that people would use the font they find
acceptable for the ligatures they want/need in each mode or buffer
where they need that. If for some reason different fonts could
determine which ligatures you do NOT want to see, then I guess we will
have to provide some easy-to-use UI for that, which would manipulate
the relevant data structures under the hood. Alternatively each font
could require a separate composition function to go with it.
See, this is exactly part of the job that still awaits us: to figure
out the various use cases for displaying ligatures in a buffer, and
then provide the necessary user-facing features to adapt Emacs to each
use case. The infrastructure for this already exists: it's the
auto-composition-mode and composition-function-table that underlies it
(although we may need to add something so that
composition-function-table could be modified on per-buffer basis), but
we lack an easy-to-use UI and customization features that will allow
users to use that machinery in practice. See the TODFO item about
ligatures; volunteers are welcome to work on that.
> The documentation of Fira Code does recommend composition-function-table here: https://github.com/tonsky/FiraCode/wiki/Emacs-instructions, but it seems like a lot of extra work for each font, isn't it?
That's for static compositions, not for automatic compositions. I was
talking about the latter, and consider the former to be a
semi-obsolete feature that we should eventually remove.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 11:23 ` Eli Zaretskii
@ 2020-05-22 12:52 ` Pip Cet
2020-05-22 13:15 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-22 12:52 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Fri, May 22, 2020 at 11:23 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Fri, 22 May 2020 09:25:31 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > > > should work, but it has weird side effects that I'm pretty sure aren't
> > > > intended (paren highlighting is broken, for example).
> > >
> > > This is not the right way.
> >
> > What is the right way, then? I want all ligatures my font supports.
>
> You can request all the ligatures that _can_ be supported;
How do I do that? Opentype fonts can support arbitrary ligatures, such
as "Zapfino" being a seven-letter ligature.
> those which
> aren't available in the font you use will not be ligated (if you use
> font-shape-gstring in the composition-function-table slot).
> Or you can request only those ligatures that make sense for the
> particular use case.
My use case is English text, and all ligatures supported by the font
make sense for that.
> For example, when displaying program source code
> you'd probably want the various symbols, like -> etc., to produce
> ligatures, but you most probably won't want "ffi" in a variable name
> to produce a ligature.
Why not?
> Or you can provide your own function to use in the
> composition-function-table, and that function can do more complex
> stuff, like refuse to ligate under some complicated conditions.
If that kind of thing turns out to be necessary, we can find ways of
doing it, such as setting a text property with harfbuzz feature
strings to be applied when rendering.
> Therefore, I think letting Lisp programs (and thus users) control what
> gets composed into ligatures and what doesn't is an important feature
> to have.
Okay, I can accept that requirement. But it should be possible to get
"all ligatures", rather than a finite set you know about in advance.
> We should develop it more, because currently it lacks some
> features we'd need for better ligature support (see the TODO item
> about that), but I think the basic design is valid.
The TODO item is confusing and, I believe, confused.
"For the list of typographical ligatures, see
https://en.wikipedia.org/wiki/Orthographic_ligature#Ligatures_in_Unicode_(Latin_alphabets)"
That's very wrong: typographical ligatures generally aren't assigned
Unicode codepoints; those that have them usually do so for historical
reasons. There's no finite "the" list of typographical ligatures, it's
up to each font to define glyphs covering codepoint clusters as it
sees fit.
I disagree with pretty much every statement in the rest of the TODO item.
> At least I didn't yet see any evidence that it isn't valid;
But how do I make it work? For English/Western text with ligatures
that I don't know about in advance? Please treat this as a dumb
end-user question. What lines of Lisp do I enter to get all the
ligatures my font supports, most of which do not have individual
Unicode codepoints?
> > Also, even if it is the wrong thing to do, why does it break seemingly
> > unrelated things?
>
> I don't know. Can you show how to reproduce that in the current
> codebase on master? Then I'll look into it.
bug#41454
> > > (set-char-table-range
> > > composition-function-table '(?f . ?f)
> > > (list (vector "ffi" 0 'compose-gstring-for-graphic)))
> >
> > > This shows how to do this only for the "ffi" ligature, but I think it
> > > makes the idea clear.
> >
> > I'm afraid it doesn't, to me.
>
> Doesn't make the idea clear or doesn't produce the ligature?
It doesn't make the idea clear, because I simply see no practical way
we're going to know about the ligatures the font provides in advance.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 12:52 ` Pip Cet
@ 2020-05-22 13:15 ` Eli Zaretskii
2020-05-22 13:29 ` Clément Pit-Claudel
2020-05-22 13:56 ` Pip Cet
0 siblings, 2 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 13:15 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Fri, 22 May 2020 12:52:41 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > You can request all the ligatures that _can_ be supported;
>
> How do I do that? Opentype fonts can support arbitrary ligatures, such
> as "Zapfino" being a seven-letter ligature.
I thought the set of all the ligatures is known, and guided by
typography experts. Do font designers really support ligatures from
any arbitrary combination of characters? If so, where can I read
about this?
> > Or you can request only those ligatures that make sense for the
> > particular use case.
>
> My use case is English text, and all ligatures supported by the font
> make sense for that.
Which ones are those? Is there an exhaustive list of such ligatures
somewhere?
> > For example, when displaying program source code
> > you'd probably want the various symbols, like -> etc., to produce
> > ligatures, but you most probably won't want "ffi" in a variable name
> > to produce a ligature.
>
> Why not?
It makes no sense to me. Why ligate them in that use case? Program
source code isn't supposed to behave like typeset human-readable text.
> Okay, I can accept that requirement. But it should be possible to get
> "all ligatures", rather than a finite set you know about in advance.
Let's first reach an understanding of what "all ligatures" actually
means. I thought the full list of all ligatures is known in advanced
and quite small, but maybe this is wrong, see above.
> "For the list of typographical ligatures, see
>
> https://en.wikipedia.org/wiki/Orthographic_ligature#Ligatures_in_Unicode_(Latin_alphabets)"
>
> That's very wrong: typographical ligatures generally aren't assigned
> Unicode codepoints; those that have them usually do so for historical
> reasons.
Indeed, ligatures don't have to have Unicode codepoints, only some of
them are precomposed. Emacs doesn't need them to have codepoints when
we use auto-composition-mode. The reference is there only to show the
list of ligatures, and I believe the list is full regardless of the
codepoint issue. Can you point me to a larger list of ligatures made
out of ASCII letters?
> There's no finite "the" list of typographical ligatures, it's up to
> each font to define glyphs covering codepoint clusters as it sees
> fit.
Really? Any reference for this?
> > At least I didn't yet see any evidence that it isn't valid;
>
> But how do I make it work? For English/Western text with ligatures
> that I don't know about in advance? Please treat this as a dumb
> end-user question. What lines of Lisp do I enter to get all the
> ligatures my font supports, most of which do not have individual
> Unicode codepoints?
You tell Emacs that a given series of characters should be composed,
via composition-function-table, and the shaper then does the job of
providing the font glyphs for displaying that sequence.
But I don't think we should continue with these details before we have
a clear idea of whether the list of possible ligatures is really
infinite, as you seem to imply.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 11:44 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
@ 2020-05-22 13:26 ` Clément Pit-Claudel
2020-05-22 14:29 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-22 13:26 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 22/05/2020 07.44, Eli Zaretskii wrote:
>> Cc: alan@idiocy.org, emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Thu, 21 May 2020 16:51:47 -0400
>>
>> On 21/05/2020 15.08, Eli Zaretskii wrote:
>>> That would prevent Emacs from controlling what is and what isn't
>>> composed, leaving the shaper in charge. We currently allow Lisp to
>>> control that via composition-function-table, which provides a regexp
>>> that text around a character must match in order for the matching
>>> substring to be passed to the shaper. We never call the shaper unless
>>> composition-function-table tells us to do so.
>>
>> Does this mean that for each font we need to re-encode the font's logic for deciding whether to use a ligature?
>
> I don't think so, but I'm not yet sure I understand all the details of
> the use cases you have in mind. See also my responses to Pip Cet:
> perhaps they answer also your questions here.
>
>> Some concrete examples: in Iosevka (*, (**, (***, (**** etc are all displayed with the * character vertically centered relative to the (, but a lone * is not centered. In Fira Code, punctuation is context-aware, so the "+" in "A + B" is not the same as the "+" in "a + b". In both of these faces, arrows can be of any length, and in Fira Code you can even mix and match them (see https://raw.githubusercontent.com/tonsky/FiraCode/master/extras/arrows.png).
>
> How do you solve this in prettify-symbols-mode?
You don't, which is unfortunate. prettify-symbols-mode was extremely cool a few years ago when fonts with programming ligatures were mostly unheard of, and it's still extremely nice for things like prettifying lambda in λ, but for things like turning ascii arrows into pretty arrows it lags behind the more recent ligature stuff.
> In general, I envision that people would use the font they find
> acceptable for the ligatures they want/need in each mode or buffer
> where they need that. If for some reason different fonts could
> determine which ligatures you do NOT want to see, then I guess we will
> have to provide some easy-to-use UI for that, which would manipulate
> the relevant data structures under the hood. Alternatively each font
> could require a separate composition function to go with it.
It would be weird for Emacs to be the only program that requires re-encoding the entire ligature logic of each font it attempts to use. Different fonts offer different ligatures, and if I want to select a subset the font itself provides variants that let me do this. Meanwhile, I hope that we can make Emacs act like browsers or other editors in that if I select a font it will just, by default, use the ligatures that this font provides according to the logic embedded in the font.
>> The documentation of Fira Code does recommend composition-function-table here: https://github.com/tonsky/FiraCode/wiki/Emacs-instructions, but it seems like a lot of extra work for each font, isn't it?
>
> That's for static compositions, not for automatic compositions. I was
> talking about the latter, and consider the former to be a
> semi-obsolete feature that we should eventually remove.
I see. I need to read up on the difference.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 13:15 ` Eli Zaretskii
@ 2020-05-22 13:29 ` Clément Pit-Claudel
2020-05-22 14:30 ` Eli Zaretskii
2020-05-22 13:56 ` Pip Cet
1 sibling, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-22 13:29 UTC (permalink / raw)
To: Eli Zaretskii, Pip Cet; +Cc: alan, emacs-devel
On 22/05/2020 09.15, Eli Zaretskii wrote:
> I thought the set of all the ligatures is known, and guided by
> typography experts.
I don't think so, at least not for programming fonts?
> Do font designers really support ligatures from
> any arbitrary combination of characters? If so, where can I read
> about this?
Yes; that's what I was alluding to in my example with comment signs and arrows. I think the pictures on https://github.com/tonsky/FiraCode should be illuminating.
I hope I'm not misunderstanding your question :/
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 13:15 ` Eli Zaretskii
2020-05-22 13:29 ` Clément Pit-Claudel
@ 2020-05-22 13:56 ` Pip Cet
[not found] ` <83lflj16jn.fsf@gnu.org>
1 sibling, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-22 13:56 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Fri, May 22, 2020 at 1:15 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Fri, 22 May 2020 12:52:41 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > > You can request all the ligatures that _can_ be supported;
> >
> > How do I do that? Opentype fonts can support arbitrary ligatures, such
> > as "Zapfino" being a seven-letter ligature.
>
> I thought the set of all the ligatures is known, and guided by
> typography experts.
No, that's not how Opentype handles things at all. I just added a "ta"
ligature to a font by converting it to ttx format, editing the XML,
and converting back to .otf. It works fine.
So ad-hoc ligatures certainly are a feature of Opentype.
> Do font designers really support ligatures from
> any arbitrary combination of characters? If so, where can I read
> about this?
https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#lookuptype-4-ligature-substitution-subtable
The font I'm looking at right now has these: Th, ch, ck, ffh, ffi,
ffj, ffk, ffl, ff, fh, fi, fj, fk, fl, ft, tt, tz
But I've also come across an example where "fä" was displayed
differently, though I'm not sure it used Opentype ligatures.
> > > For example, when displaying program source code
> > > you'd probably want the various symbols, like -> etc., to produce
> > > ligatures, but you most probably won't want "ffi" in a variable name
> > > to produce a ligature.
> >
> > Why not?
>
> It makes no sense to me. Why ligate them in that use case? Program
> source code isn't supposed to behave like typeset human-readable text.
Seems like an aesthetic decision. As far as I'm concerned, program
source code is typeset human-readable text, it just has different (and
possibly better) conventions for typesetting it. I wouldn't choose to
use a variable-pitch font for program source code ordinarily, but if I
did, I'd want ligatures.
> > "For the list of typographical ligatures, see
> >
> > https://en.wikipedia.org/wiki/Orthographic_ligature#Ligatures_in_Unicode_(Latin_alphabets)"
> >
> > That's very wrong: typographical ligatures generally aren't assigned
> > Unicode codepoints; those that have them usually do so for historical
> > reasons.
>
> Indeed, ligatures don't have to have Unicode codepoints, only some of
> them are precomposed. Emacs doesn't need them to have codepoints when
> we use auto-composition-mode. The reference is there only to show the
> list of ligatures, and I believe the list is full regardless of the
> codepoint issue. Can you point me to a larger list of ligatures made
> out of ASCII letters?
"Th" is mentioned as an example in a few places, and it's not on the list.
> But I don't think we should continue with these details before we have
> a clear idea of whether the list of possible ligatures is really
> infinite, as you seem to imply.
I agree.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 13:26 ` Clément Pit-Claudel
@ 2020-05-22 14:29 ` Eli Zaretskii
2020-05-22 14:32 ` Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 14:29 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Fri, 22 May 2020 09:26:05 -0400
>
> > In general, I envision that people would use the font they find
> > acceptable for the ligatures they want/need in each mode or buffer
> > where they need that. If for some reason different fonts could
> > determine which ligatures you do NOT want to see, then I guess we will
> > have to provide some easy-to-use UI for that, which would manipulate
> > the relevant data structures under the hood. Alternatively each font
> > could require a separate composition function to go with it.
>
> It would be weird for Emacs to be the only program that requires re-encoding the entire ligature logic of each font it attempts to use. Different fonts offer different ligatures, and if I want to select a subset the font itself provides variants that let me do this. Meanwhile, I hope that we can make Emacs act like browsers or other editors in that if I select a font it will just, by default, use the ligatures that this font provides according to the logic embedded in the font.
If this is a real problem, it should be possible to have a function
that will extract all the ligatures supported by a font, I think.
But I don't think I agree with the "logic embedded in the font" part.
I think we should let the user control which ligatures are really
used.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 13:29 ` Clément Pit-Claudel
@ 2020-05-22 14:30 ` Eli Zaretskii
2020-05-22 14:34 ` Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 14:30 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Fri, 22 May 2020 09:29:57 -0400
>
> > Do font designers really support ligatures from
> > any arbitrary combination of characters? If so, where can I read
> > about this?
>
> Yes; that's what I was alluding to in my example with comment signs and arrows. I think the pictures on https://github.com/tonsky/FiraCode should be illuminating.
>
> I hope I'm not misunderstanding your question :/
I was talking about ligatures made from letters, not symbols.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 14:29 ` Eli Zaretskii
@ 2020-05-22 14:32 ` Clément Pit-Claudel
2020-05-22 19:00 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-22 14:32 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 22/05/2020 10.29, Eli Zaretskii wrote:
>> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Fri, 22 May 2020 09:26:05 -0400
>>
>>> In general, I envision that people would use the font they find
>>> acceptable for the ligatures they want/need in each mode or buffer
>>> where they need that. If for some reason different fonts could
>>> determine which ligatures you do NOT want to see, then I guess we will
>>> have to provide some easy-to-use UI for that, which would manipulate
>>> the relevant data structures under the hood. Alternatively each font
>>> could require a separate composition function to go with it.
>>
>> It would be weird for Emacs to be the only program that requires re-encoding the entire ligature logic of each font it attempts to use. Different fonts offer different ligatures, and if I want to select a subset the font itself provides variants that let me do this. Meanwhile, I hope that we can make Emacs act like browsers or other editors in that if I select a font it will just, by default, use the ligatures that this font provides according to the logic embedded in the font.
>
> If this is a real problem, it should be possible to have a function
> that will extract all the ligatures supported by a font, I think.
>
> But I don't think I agree with the "logic embedded in the font" part.
> I think we should let the user control which ligatures are really
> used.
I agree. We should let them control the logic, but that doesn't mean we have to force them to do so; which means we need a way to extract that logic, somehow. My udnerstanding was that it could be quite complex, so there was no point in re-implementing it in ELisp.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 14:30 ` Eli Zaretskii
@ 2020-05-22 14:34 ` Clément Pit-Claudel
2020-05-22 19:01 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-22 14:34 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 22/05/2020 10.30, Eli Zaretskii wrote:
>> Cc: alan@idiocy.org, emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Fri, 22 May 2020 09:29:57 -0400
>>
>>> Do font designers really support ligatures from
>>> any arbitrary combination of characters? If so, where can I read
>>> about this?
>>
>> Yes; that's what I was alluding to in my example with comment signs and arrows. I think the pictures on https://github.com/tonsky/FiraCode should be illuminating.
>>
>> I hope I'm not misunderstanding your question :/
>
> I was talking about ligatures made from letters, not symbols.
But then how do you handle symbol ligatures? You showed the example below in response to Pip's suggestion of using .+ to support everything that I had mentioned; was that only for letters? What about symbols then?
(set-char-table-range
composition-function-table '(?f . ?f)
(list (vector "ffi" 0 'compose-gstring-for-graphic)))
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 14:32 ` Clément Pit-Claudel
@ 2020-05-22 19:00 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 19:00 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Fri, 22 May 2020 10:32:30 -0400
>
> > But I don't think I agree with the "logic embedded in the font" part.
> > I think we should let the user control which ligatures are really
> > used.
>
> I agree. We should let them control the logic, but that doesn't mean we have to force them to do so; which means we need a way to extract that logic, somehow.
If we decide to enable only the ligatures that are supported by the
default font, then yes, we should find a way of detecting which ones
it supports. But if we find out that the list of the possible
ligatures is fixed, we could by default enable all of them, and let
the shaping engine deal with those that the font doesn't support.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 14:34 ` Clément Pit-Claudel
@ 2020-05-22 19:01 ` Eli Zaretskii
2020-05-22 19:33 ` Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 19:01 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Fri, 22 May 2020 10:34:06 -0400
>
> > I was talking about ligatures made from letters, not symbols.
>
> But then how do you handle symbol ligatures?
By using suitable regular expressions. E.g., you could take the list
of ligatures in that FiraCode site and convert them into a regexp or a
set of regexps.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 19:01 ` Eli Zaretskii
@ 2020-05-22 19:33 ` Clément Pit-Claudel
2020-05-22 19:44 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-22 19:33 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 22/05/2020 15.01, Eli Zaretskii wrote:
>> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Fri, 22 May 2020 10:34:06 -0400
>>
>>> I was talking about ligatures made from letters, not symbols.
>>
>> But then how do you handle symbol ligatures?
>
> By using suitable regular expressions. E.g., you could take the list
> of ligatures in that FiraCode site and convert them into a regexp or a
> set of regexps.
Thanks. I don't understand why we need to do this, but if we have technical limitations that force us to add those regular expressions then maybe it's not the end of the world (I understand that there is value in being able to selectively disable ligatures, using regexps or something else, but it seems surprising that we'll need extra Emacs-specific work for each and every font that includes ligatures).
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 19:33 ` Clément Pit-Claudel
@ 2020-05-22 19:44 ` Eli Zaretskii
2020-05-22 20:02 ` Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-22 19:44 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Fri, 22 May 2020 15:33:59 -0400
>
> >> But then how do you handle symbol ligatures?
> >
> > By using suitable regular expressions. E.g., you could take the list
> > of ligatures in that FiraCode site and convert them into a regexp or a
> > set of regexps.
>
> Thanks. I don't understand why we need to do this
I'm not sure I follow. Do you understand why
https://github.com/tonsky/FiraCode/wiki/Emacs-instructions includes a
long list of strings to be replaced with ligatures? If so, why don't
you understand the reason we need to specify similar things when we
use automatic compositions?
And who is "we" in this case? Users of these features indeed
shouldn't need to mess with these long lists of character sequences,
but why is it a problem if "we" the Emacs developers provide data
bases of such sequences in advance, which user-facing features could
use, hiding them behind much easier UI?
> it seems surprising that we'll need extra Emacs-specific work for each and every font that includes ligatures).
I don't understand how you got to this conclusion. This is true for
prettify-symbols-mode, but that's exactly why I don't like that
implementation, and why I think automatic compositions are a better
way to go. And for automatic compositions we didn't yet decide that
any user-level action is needed when you switch to another font, we
are still discussing what is involved. Up front, I don't yet see why
such font-specific adjustment would be required from users.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-22 19:44 ` Eli Zaretskii
@ 2020-05-22 20:02 ` Clément Pit-Claudel
[not found] ` <83mu5z171j.fsf@gnu.org>
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-22 20:02 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 22/05/2020 15.44, Eli Zaretskii wrote:
>> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Fri, 22 May 2020 15:33:59 -0400
>>
>>>> But then how do you handle symbol ligatures?
>>>
>>> By using suitable regular expressions. E.g., you could take the list
>>> of ligatures in that FiraCode site and convert them into a regexp or a
>>> set of regexps.
>>
>> Thanks. I don't understand why we need to do this
>
> I'm not sure I follow. Do you understand why
> https://github.com/tonsky/FiraCode/wiki/Emacs-instructions includes a
> long list of strings to be replaced with ligatures?
Yes, I do understand: that's because Emacs' ligature support is currently weaker than other editors, and so you need to jump through hoops to use Fira Code. These hoops include telling Emacs what sequences to turn into ligatures. This problem is specific to Emacs: in other text editors, you just pick the font, and all supported ligatures are used. Importantly, the instructions on that page are a poor workaround that doesn't give you all the features of Fira Code (I don't mean that we couldn't support all of them, as I don't know if that true currently. I just mean that the page shouldn't be understood as providing full support for Fira Code in Emacs).
That's why Emacs is in the fairly short list of "Doesn't work" editors, I think.
> If so, why don't
> you understand the reason we need to specify similar things when we
> use automatic compositions?
What I don't understand is what it is about Emacs that means that we need special lists of regexps for each new font, while other editors don't need them.
> And who is "we" in this case? Users of these features indeed
> shouldn't need to mess with these long lists of character sequences,
> but why is it a problem if "we" the Emacs developers provide data
> bases of such sequences in advance, which user-facing features could
> use, hiding them behind much easier UI?
We can't provide these data bases in advance, I think. Each font supports a different set of symbol ligatures, and so the list for each font will be different.
>> it seems surprising that we'll need extra Emacs-specific work for each and every font that includes ligatures).
>
> I don't understand how you got to this conclusion. This is true for
> prettify-symbols-mode, but that's exactly why I don't like that
> implementation, and why I think automatic compositions are a better
> way to go. And for automatic compositions we didn't yet decide that
> any user-level action is needed when you switch to another font, we
> are still discussing what is involved. Up front, I don't yet see why
> such font-specific adjustment would be required from users.
Each font offers a different set of symbol ligatures: there is no common superset that covers all fonts, except the ".+" regexp that Pip posted earlier. From earlier messages, I understood that we need to specify which character sequences to ligate. So, I conclude that we'll need new work every time a new font comes out, or the ligatures in a font change (every time Fira Code is updated, for example). Since other editors don't need that work, I wonder why it's needed in Emacs.
Sorry if I misunderstood something; I don't want to waste anyone's time.
Clément.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
[not found] ` <834ks7110w.fsf@gnu.org>
@ 2020-05-23 11:24 ` Vasilij Schneidermann
2020-05-23 13:04 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Vasilij Schneidermann @ 2020-05-23 11:24 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, pipcet, emacs-devel
[-- Attachment #1: Type: text/plain, Size: 3359 bytes --]
> The reason is how the current Emacs display engine is designed: it
> cannot pass large substrings of buffer text to the shaping engine
> without incurring performance penalties and/or disrupting the way the
> layout decisions, as currently designed, work. the current design of
> the display engine is that we examine the stuff to be displayed one
> grapheme cluster at a time, and make the layout decisions after each
> grapheme cluster's metrics is produced. Unless someone begins working
> on a new design of the Emacs display, I see no good way for overcoming
> these problems, based on what I know about the display code.
Thanks for describing the problem in detail. Out of curiosity, is this the
same reason why font fallback is handled on a per-script basis for most cases
and with carefully chosen ranges for emoji? I see a similar problem there,
with updates being necessary for every Unicode release.
> Of course, it's possible that I'm missing something in the current display
> code, which could luckily allow us to support any ligature made up from any
> number of characters without any significant design changes. So please by
> all means study the current code, see if something like that is possible,
> describe such a possible solution, and I'll gladly admit my mistake. I don't
> claim a 110% understanding of all the subtleties of the current code, so it
> is perfectly possible that I'm missing something. I don't think it is good
> for Emacs to have just one person who knows these details, especially if that
> person is myself. We need to enlarge the circle of our experts on this, and
> then perhaps a practical solution could present itself. Although I'm
> skeptical, to tell the truth.
Given your previous explanation, a regex-based approach heuristic is the best
we can hope for then. From what I understand the display engine uses a
rectangular grid, not unlike what terminal emulators do. Are there any tricks
to steal from existing terminal emulators? For example there is an open pull
request [1] for alacritty using Harfbuzz and FreeType for ligature support.
> If I _am_ right, and the complete solution is impossible, we could, of course
> decide that partial solutions based on heuristics are not good enough for us,
> and wait for the redesign of the display code. I hope we will not do that,
> because IMO partial solutions that satisfy 80% of the needs are much better
> than no solutions. That is why I described how this stuff could work under
> the current limitations, albeit without supporting every possible use case.
> Eventually, this is something the community should decide.
The greatest challenge I see with redesigning the display engine is supporting
textual terminals. One alternative design would be using something akin to a
typesetting engine, like TeX's boxes and glue model or something from the roff
family (which is used successfully in terminal emulators for `man`). Another
approach is to build upon a browser engine and use copious amounts of CSS and
JavaScript to build an editor. Neither is known to be performant and power
efficient enough for continuous redisplay. It's no wonder that custom designs
are used, for example in GUI toolkits. Maybe that is the way forward?
Vasilij
[1]: https://patch-diff.githubusercontent.com/raw/alacritty/alacritty/pull/2677.patch
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
[not found] ` <831rnb0zld.fsf@gnu.org>
@ 2020-05-23 12:36 ` Pip Cet
2020-05-23 14:08 ` Eli Zaretskii
2020-05-23 12:47 ` Ligatures Stefan Monnier
1 sibling, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-23 12:36 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Sat, May 23, 2020 at 9:28 AM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sat, 23 May 2020 08:44:22 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > You write: "(b) is not really feasible without redesigning the entire
> > Emacs display engine". I don't see how that's true at all. All we need
> > is some limited look-ahead.
>
> We already have look-ahead: that's what the regexp part of the
> composition rules are about. That is not the crucial problem.
But it's the only problem I see! When you see an IT_CHARACTER, you get
some context, hand it to HarfBuzz, slice up the relevant glyphs, and
display them.
This is not complicated or difficult, except for the "get some context" part.
It doesn't involve composite.c at all, and that's good, because for
those tricky special cases composite.c does a better job than standard
shaping, and we need to keep that feature. It just shouldn't be the
regular route.
> The crucial problem is that we currently perform layout decisions one
> grapheme cluster at a time, whereas what HarfBuzz people say is that
> we should basically do that one screen line at a time.
I think we're going to have to compromise: that's why my patch used a
32-character context rather than an entire line or just a single
character.
Ideally, of course, in most real cases we'd use whitespace-delimited
words as chunks. That's mere optimization, though.
> A secondary (but important) problem is that character composition
> involves calls to Lisp, which is relatively slow. This precludes
> calling the shaper for too many characters at once, too many times for
> each redisplay cycle of a window.
I agree we shouldn't go through Lisp. My patch didn't.
Calling the shaper less often is an important optimization, too. For
whitespace-delimited words, we only need to call it once.
> > I think at the heart of it, it's about whether we treat fonts like
> > pieces of software, to be given a specific task and fixed if they fail
> > to perform it, or as bitmaps for simulating a TTY. Fonts are software:
> > they're written in a weird limited language, but essentially they're
> > programs to measure and display characters as glyphs.
>
> I don't think there's any disagreements on this high and abstract
> level.
I think there are: if we treat fonts as programs, we need to let them
do their job, which involves kerning, substitutions, ligatures, and
even crazy stuff like randomizing the glyph used for each character to
get a more hand-written appearance. We don't need to know about
ligatures, we just let the font do it. No Lisp callbacks, just a call
to harfbuzz.
> The problem is how to support that within the limits of the
> current design of the display engine.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
[not found] ` <831rnb0zld.fsf@gnu.org>
2020-05-23 12:36 ` Pip Cet
@ 2020-05-23 12:47 ` Stefan Monnier
2020-05-23 13:10 ` Ligatures Eli Zaretskii
` (2 more replies)
1 sibling, 3 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-23 12:47 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, Pip Cet, emacs-devel
> The crucial problem is that we currently perform layout decisions one
> grapheme cluster at a time, whereas what HarfBuzz people say is that
> we should basically do that one screen line at a time.
I wonder how it is supposed to work and it works in other applications:
Disregarding the theoretical question of whether a font can use
ligatures that involve the LF character (and hence affect the definition
of what is a line), I still see a chicken-and-egg problems:
How do you know where the current "screen line" ends if you don't know
how narrow/wide the font and its ligatures will render the text?
Do current applications use a heuristic like "ligatures won't reduce the
size by more than a factor 2, so estimate the lower bound on the final
size to be at most half of what the font metrics say", so they will send
up to twice as much text to be shaped as needed, and then they throw
away the left overs?
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 11:24 ` Vasilij Schneidermann
@ 2020-05-23 13:04 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-23 13:04 UTC (permalink / raw)
To: Vasilij Schneidermann; +Cc: cpitclaudel, alan, pipcet, emacs-devel
> Date: Sat, 23 May 2020 13:24:12 +0200
> From: Vasilij Schneidermann <mail@vasilij.de>
> Cc: emacs-devel@gnu.org, pipcet@gmail.com, cpitclaudel@gmail.com,
> alan@idiocy.org
>
> Out of curiosity, is this the same reason why font fallback is
> handled on a per-script basis for most cases and with carefully
> chosen ranges for emoji? I see a similar problem there, with
> updates being necessary for every Unicode release.
No, our font selection machinery is completely separate from text
shaping, and is also agnostic to character compositions. Basically,
we have a char-table (the one set-fontset-font manipulates) which
provides the various fonts to try for every given character, and some
very convoluted code (see fontset.c) that implements the logic of how
to try the fonts and which fonts to prefer for a character. IOW, the
font selection is basically per-character and not per-script.
The relation to emoji is that emoji _sequences_ need character
composition, and Emacs currently cannot compose characters that aren't
supported by the same font. This _is_ related to ligatures etc., as
it indeed touches on one of the basic premises of the display engine's
iteration through buffer text: we stop wherever the 'face' property of
characters changes (and the font is one attribute of the face), then
continue after loading and realizing the new face. This is why you
see strange artifacts when you press and hold Shift, and then move
with arrow keys across the Arabic line in etc/HELLO: the shaping of
adjacent characters breaks because we pass only part of the text to
the shaper. This is another bug that cannot be fixed cleanly while
keeping the current design of the display engine and its low-level
method of iteration through text and of producing glyphs.
> Given your previous explanation, a regex-based approach heuristic is the best
> we can hope for then. From what I understand the display engine uses a
> rectangular grid, not unlike what terminal emulators do.
It uses a rectangular array of glyphs, not a rectangular grid. The
difference is that glyphs can have variable metrics, which breaks the
grid concept. IOW, the glyph at coordinates (i, j) in the array and
the glyph at (i, j+1) are not necessarily one above the other on
display.
> Are there any tricks
> to steal from existing terminal emulators? For example there is an open pull
> request [1] for alacritty using Harfbuzz and FreeType for ligature support.
I cannot claim I understood well enough what this attempts to do, but
I don't think this is our problem in Emacs. It is not a problem of
layout per se -- Emacs is well equipped to deal with layout of glyphs
and grapheme clusters that have wildly different metrics (recall that
we are able to lay out images of more-or-less arbitrary dimensions on
the same line as simple text). The problem is that we make the layout
decisions as soon as we have the glyph metrics, on the fly, for each
"thing" we need to display. HarfBuzz people would like us to send
them the entire paragraph of text, then get it back as a series of
glyphs, then make the layout decisions based on that. This would need
entirely different algorithms, if not also different data structures;
for starters, we'd need to know how to find the paragraph(s) that will
end up on display without first trying to display them. And all our
redisplay shortcuts and optimizations implicitly also assume the
current basic iteration, one character at a time, which can be started
at any arbitrary buffer position.
> The greatest challenge I see with redesigning the display engine is supporting
> textual terminals.
Really? Why do you think this to be the greatest challenge? For any
model of the display we will come up, TTY frames will always be a
proper subset, no?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-23 12:47 ` Ligatures Stefan Monnier
@ 2020-05-23 13:10 ` Eli Zaretskii
2020-05-23 13:45 ` Ligatures Stefan Monnier
2020-05-23 13:36 ` Ligatures 조성빈
2020-05-23 14:37 ` Ligatures Pip Cet
2 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-23 13:10 UTC (permalink / raw)
To: Stefan Monnier; +Cc: cpitclaudel, alan, pipcet, emacs-devel
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Pip Cet <pipcet@gmail.com>, cpitclaudel@gmail.com, alan@idiocy.org,
> emacs-devel@gnu.org
> Date: Sat, 23 May 2020 08:47:57 -0400
>
> I wonder how it is supposed to work and it works in other applications:
I have no idea. If someone does, it would be good to hear the
details.
> Do current applications use a heuristic like "ligatures won't reduce the
> size by more than a factor 2, so estimate the lower bound on the final
> size to be at most half of what the font metrics say", so they will send
> up to twice as much text to be shaped as needed, and then they throw
> away the left overs?
As I wrote elsewhere, HarfBuzz developers actually prefer to see the
entire paragraph, not just screen line, because some shaping decisions
depend on that. Not sure what the other applications do about that.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-23 12:47 ` Ligatures Stefan Monnier
2020-05-23 13:10 ` Ligatures Eli Zaretskii
@ 2020-05-23 13:36 ` 조성빈
2020-05-23 14:15 ` Ligatures Stefan Monnier
2020-05-23 14:37 ` Ligatures Pip Cet
2 siblings, 1 reply; 145+ messages in thread
From: 조성빈 @ 2020-05-23 13:36 UTC (permalink / raw)
To: Stefan Monnier; +Cc: Eli Zaretskii, cpitclaudel, alan, Pip Cet, emacs-devel
Stefan Monnier <monnier@iro.umontreal.ca> 작성:
>> The crucial problem is that we currently perform layout decisions one
>> grapheme cluster at a time, whereas what HarfBuzz people say is that
>> we should basically do that one screen line at a time.
>
> I wonder how it is supposed to work and it works in other applications:
I don’t know how much you know about text rendering, (I’m fairly confident
that a previous Emacs maintainer to know more about this than me) but for
people who are curious about this, I found the ’Text Rendering Hates
You’[0] article which was very helpful for understanding the problem.
[0]: https://gankra.github.io/blah/text-hates-you/
> Disregarding the theoretical question of whether a font can use
> ligatures that involve the LF character (and hence affect the definition
> of what is a line), I still see a chicken-and-egg problems:
> How do you know where the current "screen line" ends if you don't know
> how narrow/wide the font and its ligatures will render the text?
>
> Do current applications use a heuristic like "ligatures won't reduce the
> size by more than a factor 2, so estimate the lower bound on the final
> size to be at most half of what the font metrics say", so they will send
> up to twice as much text to be shaped as needed, and then they throw
> away the left overs?
According to the article I mentioned, it’s just passing the total text
repeatedly until it runs out of space.
> You have to assume that your text fits on a single line and shape it
> until you run out of space. At that point you can perform layout
> operations and figure out where to break the text and start the next
> line. Repeat until everything is shaped and laid out.
>
> Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-23 13:10 ` Ligatures Eli Zaretskii
@ 2020-05-23 13:45 ` Stefan Monnier
2020-05-23 14:12 ` Ligatures Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Stefan Monnier @ 2020-05-23 13:45 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, pipcet, emacs-devel
>> Do current applications use a heuristic like "ligatures won't reduce the
>> size by more than a factor 2, so estimate the lower bound on the final
>> size to be at most half of what the font metrics say", so they will send
>> up to twice as much text to be shaped as needed, and then they throw
>> away the left overs?
> As I wrote elsewhere, HarfBuzz developers actually prefer to see the
> entire paragraph, not just screen line, because some shaping decisions
> depend on that. Not sure what the other applications do about that.
But the entire "paragraph" could be 10MB of text?!
Sounds like making the "long lines problem" even worse than it already is.
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 12:36 ` Pip Cet
@ 2020-05-23 14:08 ` Eli Zaretskii
2020-05-23 15:13 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-23 14:08 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 23 May 2020 12:36:56 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > > You write: "(b) is not really feasible without redesigning the entire
> > > Emacs display engine". I don't see how that's true at all. All we need
> > > is some limited look-ahead.
> >
> > We already have look-ahead: that's what the regexp part of the
> > composition rules are about. That is not the crucial problem.
>
> But it's the only problem I see!
Then maybe I don't understand what you mean by look-ahead. Is that
the decision how to choose those 32 characters of "context"? Then why
not use the current regexp-based approach, which is already much
smarter than just blindly taking a fixed amount of surrounding text?
> When you see an IT_CHARACTER, you get some context, hand it to
> HarfBuzz, slice up the relevant glyphs, and display them.
The problem is, of course, in the "some context" part. Your patch
used an arbitrary 32-character chunk of text around the character to
shape, which is of course not what the shaping engines want: they want
_all_ of the surrounding text, the entire paragraph.
Your patch also invokes the shaper twice, on the same 32 characters,
once in encode_char method and again in the text_extents method, which
is another waste. The code in composite.c caches the composed
characters to avoid that, but you bypass it.
This is okay for showing the concept, but we cannot use this in
production. There are too many arbitrary decisions and inefficient
expensive operations.
> It doesn't involve composite.c at all, and that's good, because for
> those tricky special cases composite.c does a better job than standard
> shaping, and we need to keep that feature. It just shouldn't be the
> regular route.
Of course, you never tell how to distinguish between the "tricky
special cases" for which we still need to use composite.c and friends,
and the other kind.
Moreover, the HarfBuzz guys clearly say that what we do now is wrong
for those "tricky" cases as well, so if we are going to fix that, why
fix it only for ligatures made out of ASCII characters?
> > The crucial problem is that we currently perform layout decisions one
> > grapheme cluster at a time, whereas what HarfBuzz people say is that
> > we should basically do that one screen line at a time.
>
> I think we're going to have to compromise: that's why my patch used a
> 32-character context rather than an entire line or just a single
> character.
If we are going to compromise, then why not compromise on what we
already have, which is much less than 32 characters? Why should we
enormously complicate and slow down our code without actually solving
the problem? Did you ever see ligatures that are 32-character long?
> Ideally, of course, in most real cases we'd use whitespace-delimited
> words as chunks. That's mere optimization, though.
That'd be the wrong optimization, AFAIK. E.g., some scripts don't
have whitespace separated words at all, and still need shaping. And
what exactly is whitespace for this purpose? e.g., does it include
Unicode control characters such as ZWJ?
> > A secondary (but important) problem is that character composition
> > involves calls to Lisp, which is relatively slow. This precludes
> > calling the shaper for too many characters at once, too many times for
> > each redisplay cycle of a window.
>
> I agree we shouldn't go through Lisp. My patch didn't.
Your patch hard-codes arbitrary numbers without any way to control
that from Lisp. Such code will never fly in Emacs.
> Calling the shaper less often is an important optimization, too. For
> whitespace-delimited words, we only need to call it once.
This doesn't work when the produced sequence of glyphs doesn't fit on
the screen line. What the current layout code does in this case won't
work well when you need to break a long sequence of glyphs in the
middle and then continue on the next line from where you left off on
this one. The longer the sequence of glyphs you get from the shaper
in one go, the higher the probability of hitting this issue.
The bottom line of this is that I think you will find very quickly
that the basic assumptions of the current design -- that we produce
single glyphs or very short sequences of them for each call to the
shaper -- that these assumptions bite you on every step, because the
code which deals with layout implicitly assumes this.
In short, I really don't see how this could ever work, except in a
very limited set of simple use cases. E.g., what do you do with
bidirectional text? ignore it?
> > I don't think there's any disagreements on this high and abstract
> > level.
>
> I think there are: if we treat fonts as programs, we need to let them
> do their job, which involves kerning, substitutions, ligatures, and
> even crazy stuff like randomizing the glyph used for each character to
> get a more hand-written appearance. We don't need to know about
> ligatures, we just let the font do it. No Lisp callbacks, just a call
> to harfbuzz.
I think this is a simplistic view of how the display engine works, and
I don't see how it could work in production while supporting all the
use cases we already do. I could be wrong, though, so I'm looking
forward to see you present a series of patches that do support the
existing use cases and the ligatures as well, and don't cause any
slowdown in redisplay.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-23 13:45 ` Ligatures Stefan Monnier
@ 2020-05-23 14:12 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-23 14:12 UTC (permalink / raw)
To: Stefan Monnier; +Cc: cpitclaudel, alan, pipcet, emacs-devel
> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: pipcet@gmail.com, cpitclaudel@gmail.com, alan@idiocy.org,
> emacs-devel@gnu.org
> Date: Sat, 23 May 2020 09:45:12 -0400
>
> > As I wrote elsewhere, HarfBuzz developers actually prefer to see the
> > entire paragraph, not just screen line, because some shaping decisions
> > depend on that. Not sure what the other applications do about that.
>
> But the entire "paragraph" could be 10MB of text?!
Yes. And?
> Sounds like making the "long lines problem" even worse than it already is.
Presumably, you use other algorithms and data structures to replace
the slow parts we have now. But yes, this is one of the problems that
would need to be solved by the new display engine.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-23 13:36 ` Ligatures 조성빈
@ 2020-05-23 14:15 ` Stefan Monnier
0 siblings, 0 replies; 145+ messages in thread
From: Stefan Monnier @ 2020-05-23 14:15 UTC (permalink / raw)
To: 조성빈
Cc: Eli Zaretskii, emacs-devel, cpitclaudel, Pip Cet, alan
> According to the article I mentioned, it’s just passing the total text
> repeatedly until it runs out of space.
But wouldn't that inherently imply an O(N²) complexity?
Stefan
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
[not found] ` <83mu5z171j.fsf@gnu.org>
@ 2020-05-23 14:34 ` Clément Pit-Claudel
2020-05-23 16:18 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-23 14:34 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 23/05/2020 02.47, Eli Zaretskii wrote:
>> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
>> Date: Fri, 22 May 2020 16:02:22 -0400
>>
>> What I don't understand is what it is about Emacs that means that we need special lists of regexps for each new font, while other editors don't need them.
>
> Emacs doesn't need a special list for each font. I already said that
> several times. Please look at some examples of composition rules we
> already have, for example the Arabic rules at the very end of
> misc-lang.el. Do you see any fonts mentioned there? These rules work
> with any font that supports Arabic.
The only thing I'm talking about is symbol compositions in programming fonts, and for these, we *will* need a custom list for each font, right?
>> Each font offers a different set of symbol ligatures: there is no common superset that covers all fonts, except the ".+" regexp that Pip posted earlier.
>
> I'm not yet sure this is indeed so. I didn't see any reference which
> implies that any combination of 26 ASCII letters could become a
> ligature.
I think that's where I'm confused. I'm talking of ligatures like -> and =>, which do not involve the 26 ASCII letters.
> This is a discussion that didn't yet happen. It is quite possible
> that in practice the list of ligatures we want to support is not very
> long. E.g., the list in
> https://github.com/tonsky/FiraCode/wiki/Emacs-instructions is not
> long, and I doubt manu additions to it will ever make sense for us.
As I said, this list is incomplete and broken.
> And finally, if a given font doesn't support some ligature, the
> original characters will be displayed "normally", so nothing is lost,
> and there's no need to tune the list of ligatures to each and every
> font. I said that as well several times already.
As long as you can produce a superset of all ligatures, yes. My claim is that this superset is ".+".
Otherwise, how do you handle the fact that Fira Code handles arrows of arbitrary lengths? Or is that different from ligatures?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures
2020-05-23 12:47 ` Ligatures Stefan Monnier
2020-05-23 13:10 ` Ligatures Eli Zaretskii
2020-05-23 13:36 ` Ligatures 조성빈
@ 2020-05-23 14:37 ` Pip Cet
2 siblings, 0 replies; 145+ messages in thread
From: Pip Cet @ 2020-05-23 14:37 UTC (permalink / raw)
To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel, cpitclaudel, alan
On Sat, May 23, 2020 at 12:48 PM Stefan Monnier
<monnier@iro.umontreal.ca> wrote:
> > The crucial problem is that we currently perform layout decisions one
> > grapheme cluster at a time, whereas what HarfBuzz people say is that
> > we should basically do that one screen line at a time.
>
> I wonder how it is supposed to work and it works in other applications:
That's why I'd like us to use a more advanced internal API rather than
the limited HarfBuzz API, one that asynchronously requests information
about preceding/following codepoints, incrementally informing us of
the minimum width already reached, until it can reach a decision. It
should be easy enough to put in some heuristics that work in practice
until a better shaper comes along...
> Do current applications use a heuristic like "ligatures won't reduce the
> size by more than a factor 2, so estimate the lower bound on the final
> size to be at most half of what the font metrics say", so they will send
> up to twice as much text to be shaped as needed, and then they throw
> away the left overs?
I don't know.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 14:08 ` Eli Zaretskii
@ 2020-05-23 15:13 ` Pip Cet
2020-05-23 16:34 ` Eli Zaretskii
2020-05-23 17:32 ` Eli Zaretskii
0 siblings, 2 replies; 145+ messages in thread
From: Pip Cet @ 2020-05-23 15:13 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Sat, May 23, 2020 at 2:08 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sat, 23 May 2020 12:36:56 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > > > You write: "(b) is not really feasible without redesigning the entire
> > > > Emacs display engine". I don't see how that's true at all. All we need
> > > > is some limited look-ahead.
> > >
> > > We already have look-ahead: that's what the regexp part of the
> > > composition rules are about. That is not the crucial problem.
> >
> > But it's the only problem I see!
>
> Then maybe I don't understand what you mean by look-ahead. Is that
> the decision how to choose those 32 characters of "context"?
Yes.
> Then why
> not use the current regexp-based approach, which is already much
> smarter than just blindly taking a fixed amount of surrounding text?
Because I do not know the regexp to use?
> > When you see an IT_CHARACTER, you get some context, hand it to
> > HarfBuzz, slice up the relevant glyphs, and display them.
>
> The problem is, of course, in the "some context" part. Your patch
> used an arbitrary 32-character chunk of text around the character to
> shape, which is of course not what the shaping engines want: they want
> _all_ of the surrounding text, the entire paragraph.
Which is clearly too expensive to actually give them, which is
something I didn't think it was necessary to even spell out.
> Your patch also invokes the shaper twice, on the same 32 characters,
> once in encode_char method and again in the text_extents method, which
> is another waste. The code in composite.c caches the composed
> characters to avoid that, but you bypass it.
Absolutely.
> This is okay for showing the concept, but we cannot use this in
> production. There are too many arbitrary decisions and inefficient
> expensive operations.
I agree, of course! In fact, the 32-character limit was chosen as a
reminder to myself that things would inherently be inefficient.
> > It doesn't involve composite.c at all, and that's good, because for
> > those tricky special cases composite.c does a better job than standard
> > shaping, and we need to keep that feature. It just shouldn't be the
> > regular route.
>
> Of course, you never tell how to distinguish between the "tricky
> special cases" for which we still need to use composite.c and friends,
> and the other kind.
The tricky special cases get handled as before, and come in with the
iterator .what set to IT_COMPOSITE. The standard cases come in with
.what set to IT_CHARACTER.
> Moreover, the HarfBuzz guys clearly say that what we do now is wrong
> for those "tricky" cases as well, so if we are going to fix that, why
> fix it only for ligatures made out of ASCII characters?
There's no such limitation, but, yes, ideally people would find they
don't need automatic compositions anymore...
> > > The crucial problem is that we currently perform layout decisions one
> > > grapheme cluster at a time, whereas what HarfBuzz people say is that
> > > we should basically do that one screen line at a time.
> >
> > I think we're going to have to compromise: that's why my patch used a
> > 32-character context rather than an entire line or just a single
> > character.
>
> If we are going to compromise, then why not compromise on what we
> already have, which is much less than 32 characters?
0 characters?
> Why should we
> enormously complicate and slow down our code without actually solving
> the problem?
We shouldn't.
> Did you ever see ligatures that are 32-character long?
"Zapfino" is the longest I've seen.
> > Ideally, of course, in most real cases we'd use whitespace-delimited
> > words as chunks. That's mere optimization, though.
>
> That'd be the wrong optimization, AFAIK.
Sure, but since it is exclusively an optimization, it's performance
considerations alone that will decide whether it is.
> E.g., some scripts don't
> have whitespace separated words at all, and still need shaping.
Thus "most".
> And
> what exactly is whitespace for this purpose? e.g., does it include
> Unicode control characters such as ZWJ?
Thankfully, that doesn't matter much: it's just a question of what we
optimize for, not one of what the results will look like.
So I'd say " ", "\t", and "\n" are enough, which is what the display
engine already handles specially.
> > > A secondary (but important) problem is that character composition
> > > involves calls to Lisp, which is relatively slow. This precludes
> > > calling the shaper for too many characters at once, too many times for
> > > each redisplay cycle of a window.
> >
> > I agree we shouldn't go through Lisp. My patch didn't.
>
> Your patch hard-codes arbitrary numbers without any way to control
> that from Lisp.
Yes.
> Such code will never fly in Emacs.
Of course not.
> > Calling the shaper less often is an important optimization, too. For
> > whitespace-delimited words, we only need to call it once.
>
> This doesn't work when the produced sequence of glyphs doesn't fit on
> the screen line.
> What the current layout code does in this case won't
> work well when you need to break a long sequence of glyphs in the
> middle and then continue on the next line from where you left off on
> this one.
You mean in visual-mode? Because what the current layout code does by
default is to break along any glyph boundary, and I don't see how
that's broken in any way.
> The longer the sequence of glyphs you get from the shaper
> in one go, the higher the probability of hitting this issue.
You break between the glyphs. It doesn't depend on whether you have
two or 20 or 100.
> The bottom line of this is that I think you will find very quickly
> that the basic assumptions of the current design -- that we produce
> single glyphs or very short sequences of them for each call to the
> shaper -- that these assumptions bite you on every step, because the
> code which deals with layout implicitly assumes this.
The shaper interface I described would actually return a single glyph
for each top-level call, with a number of callbacks to provide
context. So that assumption would hold up very well indeed...
> In short, I really don't see how this could ever work, except in a
> very limited set of simple use cases. E.g., what do you do with
> bidirectional text? ignore it?
A bidi boundary is a hard boundary for HarfBuzz, and no shaping
happens across it. Is that what you mean by "ignore it"?
> > > I don't think there's any disagreements on this high and abstract
> > > level.
> >
> > I think there are: if we treat fonts as programs, we need to let them
> > do their job, which involves kerning, substitutions, ligatures, and
> > even crazy stuff like randomizing the glyph used for each character to
> > get a more hand-written appearance. We don't need to know about
> > ligatures, we just let the font do it. No Lisp callbacks, just a call
> > to harfbuzz.
>
> I think this is a simplistic view of how the display engine works,
Quite possibly :-)
> and
> I don't see how it could work in production while supporting all the
> use cases we already do.
It only comes in for use cases not handled otherwise, i.e. those where
the iterator is at an IT_CHARACTER. All other use cases are
unaffected, because they mean we're overriding the font decision
anyway.
As I said, the problem I have is to get look-ahead working, which you
think isn't a problem. I've got an idea for it, but it doesn't work
(yet); my theory is the bidi.c code fails to keep its state in the
iterator and can't deal with multiple parallel iterators.
> I could be wrong, though, so I'm looking
> forward to see you present a series of patches that do support the
> existing use cases and the ligatures as well, and don't cause any
> slowdown in redisplay.
As I said, what's stopping me is the look-ahead problem, and in
particular some code in bidi.c that doesn't play along well with
look-ahead.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 14:34 ` Clément Pit-Claudel
@ 2020-05-23 16:18 ` Eli Zaretskii
2020-05-23 16:37 ` Clément Pit-Claudel
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-23 16:18 UTC (permalink / raw)
To: Clément Pit-Claudel; +Cc: alan, pipcet, emacs-devel
> Cc: pipcet@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Sat, 23 May 2020 10:34:23 -0400
>
> > Emacs doesn't need a special list for each font. I already said that
> > several times. Please look at some examples of composition rules we
> > already have, for example the Arabic rules at the very end of
> > misc-lang.el. Do you see any fonts mentioned there? These rules work
> > with any font that supports Arabic.
>
> The only thing I'm talking about is symbol compositions in programming fonts, and for these, we *will* need a custom list for each font, right?
No, we won't need custom lists. Not if we will use the same character
composition machinery as we use now for Arabic and other scripts that
require it.
> > And finally, if a given font doesn't support some ligature, the
> > original characters will be displayed "normally", so nothing is lost,
> > and there's no need to tune the list of ligatures to each and every
> > font. I said that as well several times already.
>
> As long as you can produce a superset of all ligatures, yes. My claim is that this superset is ".+".
It cannot be literally ".+", if you are talking about symbols, because
(a) not every character starts a symbol, and (b) symbols cannot be of
arbitrary length.
> Otherwise, how do you handle the fact that Fira Code handles arrows
> of arbitrary lengths?
We won't handle arrows of arbitrary length, no. Not as long as we
keep the current design of the display engine.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 15:13 ` Pip Cet
@ 2020-05-23 16:34 ` Eli Zaretskii
2020-05-23 22:38 ` Pip Cet
2020-05-23 17:32 ` Eli Zaretskii
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-23 16:34 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 23 May 2020 15:13:38 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > > Calling the shaper less often is an important optimization, too. For
> > > whitespace-delimited words, we only need to call it once.
> >
> > This doesn't work when the produced sequence of glyphs doesn't fit on
> > the screen line.
>
> > What the current layout code does in this case won't
> > work well when you need to break a long sequence of glyphs in the
> > middle and then continue on the next line from where you left off on
> > this one.
>
> You mean in visual-mode?
Not just in visual-line-mode, but also for the default line
continuation.
> Because what the current layout code does by default is to break
> along any glyph boundary, and I don't see how that's broken in any
> way.
The code assumes that breaking on some glyph leaves the buffer
iterator ('struct it') in a state that we can simply continue to the
next buffer position. But if you already picked up several characters
via look-ahead, that is not true, and you will have to return back
several character positions, in order to continue on the next screen
line. The whole convoluted logic of display_line (and a similar one
in move_it_in_display_line_to) is based on the assumption that this
line-wrap decisions are made as soon as a single glyph is produced;
that code will need to be rewritten if this assumption breaks. And
since the code is already hairy, to say the least, I cannot even
imagine what it will look like after such rewriting.
This is just a small example of how deep are the current design
assumptions entrenched in the code. I don't see how this can be
resolved to yield code that is readable and maintainable without
changing the design. Again, maybe I'm missing something.
> > In short, I really don't see how this could ever work, except in a
> > very limited set of simple use cases. E.g., what do you do with
> > bidirectional text? ignore it?
>
> A bidi boundary is a hard boundary for HarfBuzz, and no shaping
> happens across it. Is that what you mean by "ignore it"?
I don't mean the boundary, I meant the fact that clusters need to be
reordered.
> > I don't see how it could work in production while supporting all the
> > use cases we already do.
>
> It only comes in for use cases not handled otherwise, i.e. those where
> the iterator is at an IT_CHARACTER. All other use cases are
> unaffected, because they mean we're overriding the font decision
> anyway.
I see no reason to add such patches just to handle some simple enough
use cases. If we want the shaper to handle all the text we display,
we should go all the way and do it for any text, ASCII, non-ASCII,
symbols, emoji, everything. The current codebase is already very
difficult to understand and modify; you seem to suggest to make it
even more so, and on top of that solve only a small part of the
underlying problem. That makes very little sense to me.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 16:18 ` Eli Zaretskii
@ 2020-05-23 16:37 ` Clément Pit-Claudel
0 siblings, 0 replies; 145+ messages in thread
From: Clément Pit-Claudel @ 2020-05-23 16:37 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: alan, pipcet, emacs-devel
On 23/05/2020 12.18, Eli Zaretskii wrote:
> We won't handle arrows of arbitrary length, no. Not as long as we
> keep the current design of the display engine.
Ah, OK, then I understand.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 15:13 ` Pip Cet
2020-05-23 16:34 ` Eli Zaretskii
@ 2020-05-23 17:32 ` Eli Zaretskii
2020-05-23 21:29 ` Pip Cet
1 sibling, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-23 17:32 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 23 May 2020 15:13:38 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> As I said, the problem I have is to get look-ahead working, which you
> think isn't a problem. I've got an idea for it, but it doesn't work
> (yet); my theory is the bidi.c code fails to keep its state in the
> iterator and can't deal with multiple parallel iterators.
>
> > I could be wrong, though, so I'm looking
> > forward to see you present a series of patches that do support the
> > existing use cases and the ligatures as well, and don't cause any
> > slowdown in redisplay.
>
> As I said, what's stopping me is the look-ahead problem, and in
> particular some code in bidi.c that doesn't play along well with
> look-ahead.
I don't think you understand the depth of the issue. If we are going
to send large chunks of text to the shaping engine, then none of the
insane complexity of bidi.c makes sense; we should simply throw all of
it away and use a very different, batch-style reordering code, of the
kind you can find in the freebidi library. The sole reason for
bidi.c's existence is to produce character positions in the _visual_
order, one position at a time, something that no other bidi-aware
editor does.
Moreover, not even the basic iteration, one level above bidi.c, where
we call get_next_display_element, then PRODUCE_GLYPHS, then
set_iterator_to_next -- not even that makes sense. This basic loop
exists only because we examine characters one by one, switching from
buffer text to overlay or display strings, then back, as needed, and
applying faces as we go. Doing this in large chunks calls for a very
different structure of the code, and very different separation into
layers.
This needs to be carefully designed in advance in a clean and
well-defined way, not lumped one patch upon another until it kinda
works...
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 17:32 ` Eli Zaretskii
@ 2020-05-23 21:29 ` Pip Cet
2020-05-24 15:19 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-23 21:29 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Sat, May 23, 2020 at 5:32 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sat, 23 May 2020 15:13:38 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > As I said, the problem I have is to get look-ahead working, which you
> > think isn't a problem. I've got an idea for it, but it doesn't work
> > (yet); my theory is the bidi.c code fails to keep its state in the
> > iterator and can't deal with multiple parallel iterators.
> >
> > > I could be wrong, though, so I'm looking
> > > forward to see you present a series of patches that do support the
> > > existing use cases and the ligatures as well, and don't cause any
> > > slowdown in redisplay.
> >
> > As I said, what's stopping me is the look-ahead problem, and in
> > particular some code in bidi.c that doesn't play along well with
> > look-ahead.
>
> I don't think you understand the depth of the issue.
I think I do, actually. It's just that you'd prefer the display engine
to be torn out by the roots and rewritten in one fell swoop, but that
option isn't currently on the table.
> If we are going
> to send large chunks of text to the shaping engine, then none of the
> insane complexity of bidi.c makes sense; we should simply throw all of
> it away and use a very different, batch-style reordering code, of the
> kind you can find in the freebidi library. The sole reason for
> bidi.c's existence is to produce character positions in the _visual_
> order, one position at a time, something that no other bidi-aware
> editor does.
Yes, except we're not talking about "large chunks of text" here:
somehow you went from "we need only a bunch of regexps to catch
ligatures" to "we need to send entire paragraphs to the shaping
engine, nothing less will do". My opinion is that we need a reasonable
amount of context, often just a single character, and I see no reason
to throw out the entire display engine because we want some
look-ahead.
> Moreover, not even the basic iteration, one level above bidi.c, where
> we call get_next_display_element, then PRODUCE_GLYPHS, then
> set_iterator_to_next -- not even that makes sense.
Again, a single character of lookahead in the typical case, four
characters for most ligatures; that doesn't push us over the line to
"only a complete rewrite makes sense".
> This basic loop
> exists only because we examine characters one by one, switching from
> buffer text to overlay or display strings, then back, as needed, and
> applying faces as we go. Doing this in large chunks calls for a very
> different structure of the code, and very different separation into
> layers.
Indeed. Which is why I'm not talking about doing it in large chunks,
at this point. Let's keep doing it character by character but add what
little we need to in order to look ahead a little.
> This needs to be carefully designed in advance in a clean and
> well-defined way, not lumped one patch upon another until it kinda
> works...
I agree "just start hacking on it with no understanding of the code
until things appear to start working" is a bad strategy. So is "first,
redesign the universe". To me, it seems like what I want is a
reasonable compromise: not large chunks of text, because we can't do
that, but some context, enough to do kerning and deal with ligatures.
Remember that this discussion started when I mentioned that I was
unhappy with HarfBuzz, and I still am, precisely because of its
"first, send me your entire document" approach. I don't think it's the
right approach to take this design flaw of HarfBuzz for granted and
conclude that we need to rewrite the Emacs display engine before we
can get English ligatures to display properly.
If, that is, we can get look-ahead to work.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 16:34 ` Eli Zaretskii
@ 2020-05-23 22:38 ` Pip Cet
2020-05-24 15:33 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-23 22:38 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Sat, May 23, 2020 at 4:34 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sat, 23 May 2020 15:13:38 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> > Because what the current layout code does by default is to break
> > along any glyph boundary, and I don't see how that's broken in any
> > way.
>
> The code assumes that breaking on some glyph leaves the buffer
> iterator ('struct it') in a state that we can simply continue to the
> next buffer position.
Yes. I see no reason to change that.
> But if you already picked up several characters
> via look-ahead, that is not true, and you will have to return back
> several character positions, in order to continue on the next screen
> line.
You're describing why look-ahead is difficult: a while ago, you
appeared to be saying it wasn't. This confuses me.
Obviously, when I say "look-ahead", I mean receiving the next display
elements an iterator would produce if it were actually advanced,
without advancing it.
An easy, but potentially slow, way of doing that is to copy the
iterator to a new one, advance that, retrieve the display elements,
then throw away the copied iterator and return.
> The whole convoluted logic of display_line (and a similar one
> in move_it_in_display_line_to) is based on the assumption that this
> line-wrap decisions are made as soon as a single glyph is produced;
> that code will need to be rewritten if this assumption breaks.
I see no reason to break that assumption.
> And
> since the code is already hairy, to say the least, I cannot even
> imagine what it will look like after such rewriting.
Good thing I'm not planning to do that, then.
> This is just a small example of how deep are the current design
> assumptions entrenched in the code.
One I don't understand, because those fundamental design assumptions
aren't something I'm willing to break at this point.
> > > In short, I really don't see how this could ever work, except in a
> > > very limited set of simple use cases. E.g., what do you do with
> > > bidirectional text? ignore it?
> >
> > A bidi boundary is a hard boundary for HarfBuzz, and no shaping
> > happens across it. Is that what you mean by "ignore it"?
>
> I don't mean the boundary, I meant the fact that clusters need to be
> reordered.
I see no fundamental problem there, certainly not of the "I don't see
how this could ever work" variety.
> > > I don't see how it could work in production while supporting all the
> > > use cases we already do.
> >
> > It only comes in for use cases not handled otherwise, i.e. those where
> > the iterator is at an IT_CHARACTER. All other use cases are
> > unaffected, because they mean we're overriding the font decision
> > anyway.
>
> I see no reason to add such patches just to handle some simple enough
> use cases.
If it's so simple to get ligatures and kerning right, please tell me
how to do it.
> If we want the shaper to handle all the text we display,
Do we? A while back you said Lisp control over compositions was an
important feature, and I'm inclined to think we shouldn't break the
existing composition code.
> we should go all the way and do it for any text, ASCII, non-ASCII,
> symbols, emoji, everything.
Are you suggesting I'm somehow limiting myself to ASCII? Let me assure
you that's not the case.
> The current codebase is already very
> difficult to understand and modify;
I agree with that.
> you seem to suggest to make it
> even more so,
Well, yes, it's not going to be a free feature. The changes are
comparatively tiny compared to what else has been done to xdisp.c.
> and on top of that solve only a small part of the
> underlying problem.
Ligatures and kerning (right now, for LTR text). Is that a small
problem because of the lack of RTL support?
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 21:29 ` Pip Cet
@ 2020-05-24 15:19 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-24 15:19 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 23 May 2020 21:29:32 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > If we are going
> > to send large chunks of text to the shaping engine, then none of the
> > insane complexity of bidi.c makes sense; we should simply throw all of
> > it away and use a very different, batch-style reordering code, of the
> > kind you can find in the freebidi library. The sole reason for
> > bidi.c's existence is to produce character positions in the _visual_
> > order, one position at a time, something that no other bidi-aware
> > editor does.
>
> Yes, except we're not talking about "large chunks of text" here:
> somehow you went from "we need only a bunch of regexps to catch
> ligatures" to "we need to send entire paragraphs to the shaping
> engine, nothing less will do".
The former is what we do now. If you want to treat fonts as software,
then the HarfBuzz guys tell us we need to pass all the text through
the shaper.
> My opinion is that we need a reasonable amount of context, often
> just a single character, and I see no reason to throw out the entire
> display engine because we want some look-ahead.
The problem is to determine how much of surrounding text is needed.
The answer I was given was "all of it". So if we want to do it right,
that is what we should do. What you propose stops short of that goal,
so it's yet another partial solution. Doing that to avoid the need of
specifying a fixed set of ligatures in advance sounds like a lot of
pain for minimal gain to me.
> Remember that this discussion started when I mentioned that I was
> unhappy with HarfBuzz, and I still am, precisely because of its
> "first, send me your entire document" approach.
I'm familiar with 3 shaping engines, and they all behave like that.
So this is not an idiosyncrasy of HarfBuzz, it's how text-shaping
works in general.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-23 22:38 ` Pip Cet
@ 2020-05-24 15:33 ` Eli Zaretskii
2020-05-26 18:13 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-24 15:33 UTC (permalink / raw)
To: Pip Cet; +Cc: cpitclaudel, alan, emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 23 May 2020 22:38:18 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> On Sat, May 23, 2020 at 4:34 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > > From: Pip Cet <pipcet@gmail.com>
> > > Date: Sat, 23 May 2020 15:13:38 +0000
> > > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> > > Because what the current layout code does by default is to break
> > > along any glyph boundary, and I don't see how that's broken in any
> > > way.
> >
> > The code assumes that breaking on some glyph leaves the buffer
> > iterator ('struct it') in a state that we can simply continue to the
> > next buffer position.
>
> Yes. I see no reason to change that.
>
> > But if you already picked up several characters
> > via look-ahead, that is not true, and you will have to return back
> > several character positions, in order to continue on the next screen
> > line.
>
> You're describing why look-ahead is difficult: a while ago, you
> appeared to be saying it wasn't. This confuses me.
>
> Obviously, when I say "look-ahead", I mean receiving the next display
> elements an iterator would produce if it were actually advanced,
> without advancing it.
That's not what you said earlier:
> > > > > You write: "(b) is not really feasible without redesigning the entire
> > > > > Emacs display engine". I don't see how that's true at all. All we need
> > > > > is some limited look-ahead.
> > > >
> > > > We already have look-ahead: that's what the regexp part of the
> > > > composition rules are about. That is not the crucial problem.
> > >
> > > But it's the only problem I see!
> >
> > Then maybe I don't understand what you mean by look-ahead. Is that
> > the decision how to choose those 32 characters of "context"?
>
> Yes.
Here you said that look-ahead means how to _choose_ the context. Now
you are saying something very different: that look-ahead is how to
advance the iterator without advancing it. It's a small wonder we are
going in circles when the same term is used for two very different
things.
> > If we want the shaper to handle all the text we display,
>
> Do we? A while back you said Lisp control over compositions was an
> important feature, and I'm inclined to think we shouldn't break the
> existing composition code.
>
> > we should go all the way and do it for any text, ASCII, non-ASCII,
> > symbols, emoji, everything.
>
> Are you suggesting I'm somehow limiting myself to ASCII? Let me assure
> you that's not the case.
Then I really don't understand what problem are you trying to solve.
Let's try again from the beginning: which parts of the code that
implements automatic compositions are you trying to avoid, and why?
Is that the part that identifies the "context" via regular
expressions? If so, then this problem needs to be solved by some
alternative; using an arbitrary chosen fixed number of characters is
not suitable for production. You haven't yet shown any viable
alternative.
Assuming that the alternative for selecting the "context" is found,
and composite.c is augmented to apply it instead of the regexps, why
not use the rest of the automatic composition code to produce the
glyphs and display them? The code which does that exists and works,
and is tested by years of use. It already solves the problems of
look-ahead, of wrapping long lines, and others, including (but not
limited to) the dreaded bidi thing. Why reinvent that wheel when we
already have it, and it works well?
> > and on top of that solve only a small part of the
> > underlying problem.
>
> Ligatures and kerning (right now, for LTR text). Is that a small
> problem because of the lack of RTL support?
Yes, of course. An acceptable solution should support any text Emacs
supports. What's more, we already have the code which implements all
that, so I don't understand why you want to bypass it. Please
explain.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-24 15:33 ` Eli Zaretskii
@ 2020-05-26 18:13 ` Pip Cet
2020-05-26 19:46 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-26 18:13 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: cpitclaudel, alan, emacs-devel
On Sun, May 24, 2020 at 3:33 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Sat, 23 May 2020 22:38:18 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > On Sat, May 23, 2020 at 4:34 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > > > From: Pip Cet <pipcet@gmail.com>
> > > > Date: Sat, 23 May 2020 15:13:38 +0000
> > > > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> > > > Because what the current layout code does by default is to break
> > > > along any glyph boundary, and I don't see how that's broken in any
> > > > way.
> > >
> > > The code assumes that breaking on some glyph leaves the buffer
> > > iterator ('struct it') in a state that we can simply continue to the
> > > next buffer position.
> >
> > Yes. I see no reason to change that.
> >
> > > But if you already picked up several characters
> > > via look-ahead, that is not true, and you will have to return back
> > > several character positions, in order to continue on the next screen
> > > line.
> >
> > You're describing why look-ahead is difficult: a while ago, you
> > appeared to be saying it wasn't. This confuses me.
> >
> > Obviously, when I say "look-ahead", I mean receiving the next display
> > elements an iterator would produce if it were actually advanced,
> > without advancing it.
> That's not what you said earlier:
I think it is what I said.
> > > > > > You write: "(b) is not really feasible without redesigning the entire
> > > > > > Emacs display engine". I don't see how that's true at all. All we need
> > > > > > is some limited look-ahead.
> > > > >
> > > > > We already have look-ahead: that's what the regexp part of the
> > > > > composition rules are about. That is not the crucial problem.
> > > >
> > > > But it's the only problem I see!
> > >
> > > Then maybe I don't understand what you mean by look-ahead. Is that
> > > the decision how to choose those 32 characters of "context"?
> >
> > Yes.
>
> Here you said that look-ahead means how to _choose_ the context.
The distinction escapes me: look-ahead is how to get the context for a
character, obviously without ruining any persistent state. I'm puzzled
as to what else it could have meant.
> > > If we want the shaper to handle all the text we display,
> >
> > Do we? A while back you said Lisp control over compositions was an
> > important feature, and I'm inclined to think we shouldn't break the
> > existing composition code.
> >
> > > we should go all the way and do it for any text, ASCII, non-ASCII,
> > > symbols, emoji, everything.
> >
> > Are you suggesting I'm somehow limiting myself to ASCII? Let me assure
> > you that's not the case.
>
> Then I really don't understand what problem are you trying to solve.
Ligatures and kerning.
> Let's try again from the beginning: which parts of the code that
> implements automatic compositions are you trying to avoid,
> and why?
I'm not trying to avoid any of it! I just see no reason to use any of
it, so far, because the part we have in common is about a dozen lines
of code around the call to hb_shape.
> Is that the part that identifies the "context" via regular
> expressions? If so, then this problem needs to be solved by some
> alternative; using an arbitrary chosen fixed number of characters is
> not suitable for production.
I'm puzzled as to how these regular expressions, which only work when
they match fixed-length strings, as far as I can tell, are worse than
a fixed-length context. You're right that the number shouldn't be
hardcoded in Emacs, and shouldn't be arbitrary, but obviously there
has to be a limit shorter than a word or paragraph. (The composite.c
code currently hardcodes a limit of 500 characters).
(And as I've said repeatedly, this is a deficiency specifically in
HarfBuzz: the OpenType format makes it very easy to tell what the
longest pattern is and how much context is needed. HarfBuzz should
pass on that information, ideally by providing an incremental
asynchronous API that requests only as much context as is needed until
the glyphs in question can be returned.)
> You haven't yet shown any viable alternative.
To what? We still haven't seen any actual regular expressions that
work. You just keep saying "regular expressions" like that's a
solution, rather than simply constituting a restriction on the set of
possible solutions.
And keep in mind that this context is used only for deciding what the
"current" glyph looks like: the next glyph will have its own context,
which might or might not be different.
What I'm currently playing with is something that I'm not sure is even
expressible as a regexp: starting with the character at point, keep
adding surrounding characters unless doing so would create a
delimiter-nondelimiter boundary after the first char, or a
nondelimiter-delimiter boundary before the last char, but limit the
whole thing to 16 characters each way.
As I've explained, it would be much better to let HarfBuzz tell us
whether to provide more context, but even then we'd need a cut-off:
imagine a file containing a gigabyte of 'f's.
> Assuming that the alternative for selecting the "context" is found,
> and composite.c is augmented to apply it instead of the regexps, why
> not use the rest of the automatic composition code to produce the
> glyphs and display them?
I chose not to do that for a patch which I have stated repeatedly was
not in any way a finalized design, and I don't see any good reason to
do it for a real patch, either, so far.
(I'll be honest: I strongly suspect that the code is too slow, we know
it to be buggy, and it's simply too different from what I actually
want to benefit from sharing the code).
> The code which does that exists and works,
(I suspect: slowly)
> and is tested by years of use.
It's unusable for me in Emacs 26.3.
> It already solves the problems of look-ahead,
If it does so efficiently, I'll certainly try reusing that code. But I
strongly suspect it doesn't.
> of wrapping long lines,
Very poorly, for my purposes.
> and others, including (but not limited to) the dreaded bidi thing.
Looking for "bidi" in composite.c, the only relevant thing I see is a FIXME.
> Why reinvent that wheel when we already have it, and it works well?
First, because it doesn't work that well for my purposes; second,
precisely because it works well for the purposes of others, and I'd
like to have as little impact as possible on existing use cases. They
should just continue working, and so far they do.
> > > and on top of that solve only a small part of the
> > > underlying problem.
> >
> > Ligatures and kerning (right now, for LTR text). Is that a small
> > problem because of the lack of RTL support?
>
> Yes, of course.
Why? I honestly don't see what's bad about a patch that improves
things for most languages and doesn't affect RTL languages (which, as
you point out, have existing support).
The code shouldn't break horribly for RTL text (it doesn't). If it
works, that's great; if it doesn't work and leaves things unshaped,
that's the existing behavior, and auto-composition-mode will still
work if enabled.
> An acceptable solution should support any text Emacs
> supports.
By that standard, bidi.c and composite.c are unacceptable.
> What's more, we already have the code which implements all
> that, so I don't understand why you want to bypass it.
We have something that superficially results in a similar screen
layout to what I want, but that actually represents display elements
in a way that makes them unusable for my purposes.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-26 18:13 ` Pip Cet
@ 2020-05-26 19:46 ` Eli Zaretskii
2020-05-27 9:36 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-26 19:46 UTC (permalink / raw)
To: Pip Cet; +Cc: emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Tue, 26 May 2020 18:13:55 +0000
> Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
>
> > Assuming that the alternative for selecting the "context" is found,
> > and composite.c is augmented to apply it instead of the regexps, why
> > not use the rest of the automatic composition code to produce the
> > glyphs and display them?
>
> I chose not to do that for a patch which I have stated repeatedly was
> not in any way a finalized design, and I don't see any good reason to
> do it for a real patch, either, so far.
Why not? How about trying to do that before giving up?
> (I'll be honest: I strongly suspect that the code is too slow, we know
> it to be buggy, and it's simply too different from what I actually
> want to benefit from sharing the code).
>
> > The code which does that exists and works,
>
> (I suspect: slowly)
Any measurements to back that up? E.g., is scrolling through
etc/HELLO especially slow, once all the fonts were loaded (i.e. each
character in the file was displayed at least once)?
> > and is tested by years of use.
>
> It's unusable for me in Emacs 26.3.
How so? what doesn't work? (And why are you using Emacs 26 and not
Emacs 27, where we support HarfBuzz and made several improvements and
bugfixes in the character composition area?)
> > It already solves the problems of look-ahead,
>
> If it does so efficiently, I'll certainly try reusing that code. But I
> strongly suspect it doesn't.
Why suspect? why not try and see what does and doesn't work, what is
and isn't efficient?
> > of wrapping long lines,
>
> Very poorly, for my purposes.
How so? what doesn't wrap correctly, and why?
> > and others, including (but not limited to) the dreaded bidi thing.
>
> Looking for "bidi" in composite.c, the only relevant thing I see is a FIXME.
That's because you look in the wrong place. Once again, try looking
at etc/HELLO, there are portions of it that need both bidi and
compositions. I can explain how it works (the code is spread over
several files), but please believe me that it does, it passed the
HarfBuzz developers' eyes most of whom are native Arabic and Farsi
speakers, and wouldn't allow us to display Arabic script incorrectly.
The whole point of using the existing code is that you don't _need_ to
understand how exactly we handle the bidi reordering when character
compositions are required. It just works, for all you care. It did
take several iterations to get right at the time; why would you want
to repeat all that, when the code is there to use and extend?
> > Why reinvent that wheel when we already have it, and it works well?
>
> First, because it doesn't work that well for my purposes;
What doesn't work? please be specific.
> second, precisely because it works well for the purposes of others,
> and I'd like to have as little impact as possible on existing use
> cases. They should just continue working, and so far they do.
You are thinking of breaking those other cases by your changes? But
we haven't yet established that changes are needed, let alone which
changes. How do you know you will break anything at all?
> > > Ligatures and kerning (right now, for LTR text). Is that a small
> > > problem because of the lack of RTL support?
> >
> > Yes, of course.
>
> Why?
Because the features you are talking about should "just work" in
Emacs. Not only for some use cases and some scripts -- that is not
how we develop features. Features that work only for some cases are
broken and will draw bug reports. They make Emacs look unclean and
unprofessional.
And there's no need to add such half-broken features because code that
supports much broader class of use cases already exists, you just need
to use it and maybe extend and augment it a bit.
> The code shouldn't break horribly for RTL text (it doesn't).
It _will_ break for RTL text, you just didn't yet see it because you
only tested it in simple use cases. UAX#9 defines a lot of optional
features, including multi-level directional overrides and embeddings,
it isn't just right-to-left vs left-to-right.
Again, there's no need for you to reinvent this wheel, we already have
it figured out.
> > What's more, we already have the code which implements all
> > that, so I don't understand why you want to bypass it.
>
> We have something that superficially results in a similar screen
> layout to what I want, but that actually represents display elements
> in a way that makes them unusable for my purposes.
Then please describe what doesn't fit your purpose, and let's focus on
extending the existing code to do what's missing. Throwing everything
away and starting anew is not the right way, it's a huge waste of
energy and time to implement something that we already have. It is
also a maintenance burden in the long run.
Please note: I'm not talking about the regexp part -- that part you
anyway will need to decide how to extend or augment. I'm telling you
right here and now that blindly taking a fixed amount of surrounding
text will not be acceptable. You can either come up with some smarter
regexp (and you are wrong: the regexps in composition-function-table
do NOT have to match only fixed strings, you can see that they don't
in the part of the table we set up for the Arabic script); or you can
decide on something more complex, like a function. Either way, the
amount of text that this will pick up and pass to the shaper should be
reasonable and should be determined by some understandable rules. And
those rules must be controllable from Lisp.
But that is a separate part of the problem that you will need to
solve, and you will need to solve it whether or not you use character
compositions. What I _am_ saying is that the rest of the machinery
that implements automatic compositions does exactly what you need: it
calls the shaper, handling LTR and RTL text as needed, then lays out
the glyphs the shaper returns in a way that handles all the usual
stuff our users expect, such as line wrapping and truncation. It is
silly to disregard that code, so please don't.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-26 19:46 ` Eli Zaretskii
@ 2020-05-27 9:36 ` Pip Cet
2020-05-27 17:13 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-27 9:36 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
On Tue, May 26, 2020 at 7:46 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Tue, 26 May 2020 18:13:55 +0000
> > Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org
> >
> > > Assuming that the alternative for selecting the "context" is found,
> > > and composite.c is augmented to apply it instead of the regexps, why
> > > not use the rest of the automatic composition code to produce the
> > > glyphs and display them?
> >
> > I chose not to do that for a patch which I have stated repeatedly was
> > not in any way a finalized design, and I don't see any good reason to
> > do it for a real patch, either, so far.
>
> Why not?
Which part are you asking about? I don't see any good reason because
I've read the composite.c code (I'm not ignoring it), with an eye to
reusing what's reusable, and come up empty.
But you've convinced me I need to do a careful rereading.
> > > The code which does that exists and works,
> >
> > (I suspect: slowly)
>
> Any measurements to back that up?
Yes. With a regexp of "....", the composite.c code takes 175 billion
cycles to display every line of composite.c. My code takes 144 billion
cycles, with a lookahead/lookbehind each set to 128 but limiting it as
described.
> E.g., is scrolling through
> etc/HELLO especially slow, once all the fonts were loaded (i.e. each
> character in the file was displayed at least once)?
> (And why are you using Emacs 26 and not
> Emacs 27, where we support HarfBuzz and made several improvements and
> bugfixes in the character composition area?)
Because I was trying to test your implication that all this was usable
years ago. It wasn't. I'm not using Emacs 26 :-)
> > > It already solves the problems of look-ahead,
> >
> > If it does so efficiently, I'll certainly try reusing that code. But I
> > strongly suspect it doesn't.
>
> Why suspect? why not try and see what does and doesn't work, what is
> and isn't efficient?
I have, now, coming up with the above measurement which confirms my suspicion.
> > > and others, including (but not limited to) the dreaded bidi thing.
> >
> > Looking for "bidi" in composite.c, the only relevant thing I see is a FIXME.
>
> That's because you look in the wrong place.
What's the right place? I'm using all the code in bidi.c, of course,
so as far as I can tell what I'm not doing is using composite.c...
> Once again, try looking
> at etc/HELLO, there are portions of it that need both bidi and
> compositions. I can explain how it works (the code is spread over
> several files), but please believe me that it does, it passed the
> HarfBuzz developers' eyes most of whom are native Arabic and Farsi
> speakers, and wouldn't allow us to display Arabic script incorrectly.
>
> The whole point of using the existing code is that you don't _need_ to
> understand how exactly we handle the bidi reordering when character
> compositions are required.
But that's true without using the existing code!
> It just works, for all you care. It did
> take several iterations to get right at the time; why would you want
> to repeat all that, when the code is there to use and extend?
> > second, precisely because it works well for the purposes of others,
> > and I'd like to have as little impact as possible on existing use
> > cases. They should just continue working, and so far they do.
>
> You are thinking of breaking those other cases by your changes?
No! If I break them, that's a severe bug in my code!
> But
> we haven't yet established that changes are needed,
"Enter"ing ligature glyphs is definitely something we need to do
before any user can reasonably use variable-pitch fonts with ligatures
for displaying English text. Kerning is another such thing. Both don't
work with the current code.
> Because the features you are talking about should "just work" in
> Emacs.
> Not only for some use cases and some scripts -- that is not
> how we develop features. Features that work only for some cases are
> broken and will draw bug reports. They make Emacs look unclean and
> unprofessional.
Not as much as the current lack of support does.
> And there's no need to add such half-broken features because code that
> supports much broader class of use cases already exists, you just need
> to use it and maybe extend and augment it a bit.
I don't think I agree with the "a bit".
> > The code shouldn't break horribly for RTL text (it doesn't).
>
> It _will_ break for RTL text, you just didn't yet see it because you
> only tested it in simple use cases. UAX#9 defines a lot of optional
> features, including multi-level directional overrides and embeddings,
> it isn't just right-to-left vs left-to-right.
I assume bidi.c handles that, as it does for composite.c?
> > > What's more, we already have the code which implements all
> > > that, so I don't understand why you want to bypass it.
> >
> > We have something that superficially results in a similar screen
> > layout to what I want, but that actually represents display elements
> > in a way that makes them unusable for my purposes.
>
> Then please describe what doesn't fit your purpose, and let's focus on
> extending the existing code to do what's missing.
The three main things are:
- "entering" glyphs, instead of treating them as atomic
- providing context automatically rather than by providing specific
regexps for it in advance
- kerning, which requires context for every character
Secondary concerns:
- ligatures that come partly from a display property and partly from
the buffer (composite.c doesn't allow for those, as far as I can tell)
> Please note: I'm not talking about the regexp part -- that part you
> anyway will need to decide how to extend or augment. I'm telling you
> right here and now that blindly taking a fixed amount of surrounding
> text will not be acceptable. You can either come up with some smarter
> regexp (and you are wrong: the regexps in composition-function-table
> do NOT have to match only fixed strings, you can see that they don't
> in the part of the table we set up for the Arabic script);
Again, I think the limits are fixed: 4 characters of history and 500
characters of look-ahead. What am I missing?
> or you can
> decide on something more complex, like a function. Either way, the
> amount of text that this will pick up and pass to the shaper should be
> reasonable and should be determined by some understandable rules. And
> those rules must be controllable from Lisp.
That last part isn't true for the composite.c code, which imposes a
limit of 4 characters of history and 500 characters of look-ahead, as
far as I can tell. But, sure, if that's a requirement, I'll keep it in
mind.
> But that is a separate part of the problem that you will need to
> solve, and you will need to solve it whether or not you use character
> compositions. What I _am_ saying is that the rest of the machinery
> that implements automatic compositions does exactly what you need: it
> calls the shaper, handling LTR and RTL text as needed, then lays out
> the glyphs the shaper returns in a way that handles all the usual
> stuff our users expect, such as line wrapping and truncation.
> It is silly to disregard that code, so please don't.
You've convinced me that it's worth reading it again, more carefully,
but I'm not optimistic I'll come to a different conclusion this time
around.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-27 9:36 ` Pip Cet
@ 2020-05-27 17:13 ` Eli Zaretskii
2020-05-27 18:42 ` Pip Cet
0 siblings, 1 reply; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-27 17:13 UTC (permalink / raw)
To: Pip Cet; +Cc: emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Wed, 27 May 2020 09:36:52 +0000
> Cc: emacs-devel@gnu.org
>
> > Any measurements to back that up?
>
> Yes. With a regexp of "....", the composite.c code takes 175 billion
> cycles to display every line of composite.c. My code takes 144 billion
> cycles, with a lookahead/lookbehind each set to 128 but limiting it as
> described.
What did you compare, exactly? On the one hand, the code you posted
here, which took 128 characters around each character to be displayed?
any other changes in the code you posted here? And what does
"limiting it as described" mean here?
And on the other hand, the existing automatic composition machinery?
With what setup of composition-function-table, exactly?
And finally, which code was included in the count of cycles?
> > > > and others, including (but not limited to) the dreaded bidi thing.
> > >
> > > Looking for "bidi" in composite.c, the only relevant thing I see is a FIXME.
> >
> > That's because you look in the wrong place.
>
> What's the right place? I'm using all the code in bidi.c, of course,
No, actually you don't. Your make_context copies characters in strict
logical order, bypassing bidi.c, and by that also potentially crossing
boundaries of different directionality (and even line and paragraph
boundaries), which is a no-no in text shaping. Then, after you call
the shaper, you don't reorder the glyphs it delivers, so they will
look on display in the wrong order. And there may be other subtle
issues as well -- this stuff was finalized so long ago that I'm not
even sure I remember all the details of what needed to be done to get
it right.
> > > The code shouldn't break horribly for RTL text (it doesn't).
> >
> > It _will_ break for RTL text, you just didn't yet see it because you
> > only tested it in simple use cases. UAX#9 defines a lot of optional
> > features, including multi-level directional overrides and embeddings,
> > it isn't just right-to-left vs left-to-right.
>
> I assume bidi.c handles that, as it does for composite.c?
Yes, but only _if_you_use_them_correctly_! If you bypass them, then
all bets are off.
> > > We have something that superficially results in a similar screen
> > > layout to what I want, but that actually represents display elements
> > > in a way that makes them unusable for my purposes.
> >
> > Then please describe what doesn't fit your purpose, and let's focus on
> > extending the existing code to do what's missing.
>
> The three main things are:
> - "entering" glyphs, instead of treating them as atomic
Why is that needed? A ligature is a single display entity, that's why
fonts ligate. Why would we want to break ligatures when we wrap
lines?
> - providing context automatically rather than by providing specific
> regexps for it in advance
That's a separate part of the problem; I wasn't talking about it. It
needs a separate solution (which was not yet presented), but the
solution doesn't have to be based on regexps if a better or smarter or
faster way is available. Extending composition-function-table to
support context definition by means other than regexp is easy and
doesn't disrupt the way the code works.
> - kerning, which requires context for every character
That's again about that separate part of the problem, because once the
context was determined correctly, the shaper will perform the kerning
for you.
> - ligatures that come partly from a display property and partly from
> the buffer (composite.c doesn't allow for those, as far as I can tell)
It doesn't and it shouldn't! Text of display strings and overlay
strings is completely isolated from buffer text, and is even
bidi-reordered independently. This is by design. These strings are
more akin to images than to a part of buffer text, so mixing them with
buffer text on display would be a grave mistake.
> > Please note: I'm not talking about the regexp part -- that part you
> > anyway will need to decide how to extend or augment. I'm telling you
> > right here and now that blindly taking a fixed amount of surrounding
> > text will not be acceptable. You can either come up with some smarter
> > regexp (and you are wrong: the regexps in composition-function-table
> > do NOT have to match only fixed strings, you can see that they don't
> > in the part of the table we set up for the Arabic script);
>
> Again, I think the limits are fixed: 4 characters of history and 500
> characters of look-ahead. What am I missing?
Fixed limits and fixed strings are two different things. You can
match strings of many different lengths up to a limit.
The 3 previous characters are rarely needed, certainly not for English
ligatures, because you can detect the sequence by the first character.
So this is rarely a limitation; but again, it can be expanded if
needed with little if any effect on the code.
(And where did you see the 500-character limitation of look-ahead?)
Anyway, you again focus on the (separate) issue of determining the
context. Whereas I was mainly talking about what happens _after_ you
determine the context: how do you collect the characters to pass to
the shaper, how you present to the layout code the glyphs returned by
the shaper, and how you lay out those glyphs by inserting them into
the glyph rows of the glyph matrix. It is this code that I see no
reason to modify, definitely not significantly.
> > or you can
> > decide on something more complex, like a function. Either way, the
> > amount of text that this will pick up and pass to the shaper should be
> > reasonable and should be determined by some understandable rules. And
> > those rules must be controllable from Lisp.
>
> That last part isn't true for the composite.c code, which imposes a
> limit of 4 characters of history and 500 characters of look-ahead
How do those limits violate the above requirement? The 3-char
prev-chars limit is "reasonable" because we currently don't need more,
and the other limit doesn't exist AFAICT -- you could make a regexp
that matched very long strings, if needed. And the rules to use to
set up the regexp are definitely "understandable" and can be
controlled from Lisp.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-27 17:13 ` Eli Zaretskii
@ 2020-05-27 18:42 ` Pip Cet
2020-05-27 19:19 ` Eli Zaretskii
0 siblings, 1 reply; 145+ messages in thread
From: Pip Cet @ 2020-05-27 18:42 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
On Wed, May 27, 2020 at 5:13 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Wed, 27 May 2020 09:36:52 +0000
> > Cc: emacs-devel@gnu.org
> >
> > > Any measurements to back that up?
> >
> > Yes. With a regexp of "....", the composite.c code takes 175 billion
> > cycles to display every line of composite.c. My code takes 144 billion
> > cycles, with a lookahead/lookbehind each set to 128 but limiting it as
> > described.
>
> What did you compare, exactly? On the one hand, the code you posted
> here, which took 128 characters around each character to be displayed?
No. Not anything like that code.
> any other changes in the code you posted here? And what does
> "limiting it as described" mean here?
I described the algorithm for selecting context.
> And on the other hand, the existing automatic composition machinery?
> With what setup of composition-function-table, exactly?
As I said, a regexp of "....".
> And finally, which code was included in the count of cycles?
All of it.
There's no reason to believe the composite.c regexp design will
perform adequately. It doesn't.
> > > > > and others, including (but not limited to) the dreaded bidi thing.
> > > >
> > > > Looking for "bidi" in composite.c, the only relevant thing I see is a FIXME.
> > >
> > > That's because you look in the wrong place.
> >
> > What's the right place? I'm using all the code in bidi.c, of course,
>
> No, actually you don't.
> Your make_context copies characters in strict
> logical order, bypassing bidi.c
My current code doesn't.
> , and by that also potentially crossing
> boundaries of different directionality (and even line and paragraph
> boundaries), which is a no-no in text shaping. Then, after you call
> the shaper, you don't reorder the glyphs it delivers, so they will
> look on display in the wrong order.
I do now.
> And there may be other subtle
> issues as well -- this stuff was finalized so long ago that I'm not
> even sure I remember all the details of what needed to be done to get
> it right.
(It's not enough. Open emacs -Q etc/HELLO, place point on the lam in
"aleikum", and hit control-space. The shape changes to something
incorrect.)
> > > > The code shouldn't break horribly for RTL text (it doesn't).
> > >
> > > It _will_ break for RTL text, you just didn't yet see it because you
> > > only tested it in simple use cases. UAX#9 defines a lot of optional
> > > features, including multi-level directional overrides and embeddings,
> > > it isn't just right-to-left vs left-to-right.
> >
> > I assume bidi.c handles that, as it does for composite.c?
>
> Yes, but only _if_you_use_them_correctly_! If you bypass them, then
> all bets are off.
Obviously.
> > > > We have something that superficially results in a similar screen
> > > > layout to what I want, but that actually represents display elements
> > > > in a way that makes them unusable for my purposes.
> > >
> > > Then please describe what doesn't fit your purpose, and let's focus on
> > > extending the existing code to do what's missing.
> >
> > The three main things are:
> > - "entering" glyphs, instead of treating them as atomic
>
> Why is that needed? A ligature is a single display entity, that's why
> fonts ligate.
"ffi" is not. When I enter "official" C-a C-f C-f, point MUST be on
the second f.
> Why would we want to break ligatures when we wrap
> lines?
Who said we do? I personally like it, but it's obviously not something
we should do by default?
> > - providing context automatically rather than by providing specific
> > regexps for it in advance
>
> That's a separate part of the problem; I wasn't talking about it. It
> needs a separate solution (which was not yet presented), but the
> solution doesn't have to be based on regexps if a better or smarter or
> faster way is available. Extending composition-function-table to
> support context definition by means other than regexp is easy and
> doesn't disrupt the way the code works.
>
> > - kerning, which requires context for every character
>
> That's again about that separate part of the problem, because once the
> context was determined correctly, the shaper will perform the kerning
> for you.
> > - ligatures that come partly from a display property and partly from
> > the buffer (composite.c doesn't allow for those, as far as I can tell)
>
> It doesn't and it shouldn't! Text of display strings and overlay
> strings is completely isolated from buffer text, and is even
> bidi-reordered independently. This is by design.
Unacceptable design for my use case, then.
I don't see how revealing buffer text that has a replacing display
property, rather than the replacement, is good design.
The results of putting display properties on autocompositions
are...entertaining, in any case. I've now got an "x" character that
C-x = tells me is an "i"...
> These strings are
> more akin to images than to a part of buffer text, so mixing them with
> buffer text on display would be a grave mistake.
No, it wouldn't be. If two letters appear with no intervening space,
they need to be kerned and ligated if appropriate, no matter where
they come from. If people want a ZWNJ, that's perfectly available to
them.
> > > Please note: I'm not talking about the regexp part -- that part you
> > > anyway will need to decide how to extend or augment. I'm telling you
> > > right here and now that blindly taking a fixed amount of surrounding
> > > text will not be acceptable. You can either come up with some smarter
> > > regexp (and you are wrong: the regexps in composition-function-table
> > > do NOT have to match only fixed strings, you can see that they don't
> > > in the part of the table we set up for the Arabic script);
> >
> > Again, I think the limits are fixed: 4 characters of history and 500
> > characters of look-ahead. What am I missing?
>
> Fixed limits and fixed strings are two different things. You can
> match strings of many different lengths up to a limit.
Which effectively means you can match strings of that limited length.
> The 3 previous characters are rarely needed, certainly not for English
> ligatures, because you can detect the sequence by the first character.
Precisely the same argument applies to my 16-character limit. A script
in which a glyph depends on something happening 16 codepoints onwards,
or back, is extremely unlikely.
> Anyway, you again focus on the (separate) issue of determining the
> context. Whereas I was mainly talking about what happens _after_ you
> determine the context: how do you collect the characters to pass to
> the shaper, how you present to the layout code the glyphs returned by
> the shaper, and how you lay out those glyphs by inserting them into
> the glyph rows of the glyph matrix. It is this code that I see no
> reason to modify, definitely not significantly.
It needs to be modified, significantly, to support entering glyphs, to
support kerning, and to support things like ligating across a buffer
text / display string boundary.
> > > or you can
> > > decide on something more complex, like a function. Either way, the
> > > amount of text that this will pick up and pass to the shaper should be
> > > reasonable and should be determined by some understandable rules. And
> > > those rules must be controllable from Lisp.
> >
> > That last part isn't true for the composite.c code, which imposes a
> > limit of 4 characters of history and 500 characters of look-ahead
>
> How do those limits violate the above requirement? The 3-char
> prev-chars limit is "reasonable" because we currently don't need more,
It's hardcoded in C, though. A 16-character limit, as explained above,
is perfectly "reasonable" for determining the shape of a single glyph.
> and the other limit doesn't exist AFAICT -- you could make a regexp
> that matched very long strings, if needed.
Hmm. I thought I saw weirdness around the 500th character, but it's
probably one of the other bugs.
But, seriously, you're still willing to argue that point shouldn't be
able to enter the "ffi" glyph? Not even if the user wants it? Because
if so, I suggest we interrupt the discussion here.
^ permalink raw reply [flat|nested] 145+ messages in thread
* Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY))
2020-05-27 18:42 ` Pip Cet
@ 2020-05-27 19:19 ` Eli Zaretskii
0 siblings, 0 replies; 145+ messages in thread
From: Eli Zaretskii @ 2020-05-27 19:19 UTC (permalink / raw)
To: Pip Cet; +Cc: emacs-devel
> From: Pip Cet <pipcet@gmail.com>
> Date: Wed, 27 May 2020 18:42:07 +0000
> Cc: emacs-devel@gnu.org
>
> > What did you compare, exactly? On the one hand, the code you posted
> > here, which took 128 characters around each character to be displayed?
>
> No. Not anything like that code.
Then your numbers cannot be meaningfully reasoned about, because no
one knows what you did.
> There's no reason to believe the composite.c regexp design will
> perform adequately. It doesn't.
I guess in your eyes only your code performs adequately.
Sorry, this means any further discussion with you on these matters is
futile. I regret to have wasted so much time trying to explain how
this stuff works. I will try to be smarter next time when you ask
some question.
> (It's not enough. Open emacs -Q etc/HELLO, place point on the lam in
> "aleikum", and hit control-space. The shape changes to something
> incorrect.)
A known limitation of our handling of faces in conjunction with
character composition. Finding the reason is left as an exercise.
> > > - "entering" glyphs, instead of treating them as atomic
> >
> > Why is that needed? A ligature is a single display entity, that's why
> > fonts ligate.
>
> "ffi" is not. When I enter "official" C-a C-f C-f, point MUST be on
> the second f.
That doesn't require producing separate glyphs.
> > It doesn't and it shouldn't! Text of display strings and overlay
> > strings is completely isolated from buffer text, and is even
> > bidi-reordered independently. This is by design.
>
> Unacceptable design for my use case, then.
This is the design of the Emacs display engine. If it doesn't fit
your case, your case cannot be had in Emacs without rewriting the
display code.
> No, it wouldn't be. If two letters appear with no intervening space,
> they need to be kerned and ligated if appropriate, no matter where
> they come from. If people want a ZWNJ, that's perfectly available to
> them.
That's not what display and overlay strings are for in Emacs.
> > Fixed limits and fixed strings are two different things. You can
> > match strings of many different lengths up to a limit.
>
> Which effectively means you can match strings of that limited length.
Except that there's no limit, of course.
> > The 3 previous characters are rarely needed, certainly not for English
> > ligatures, because you can detect the sequence by the first character.
>
> Precisely the same argument applies to my 16-character limit. A script
> in which a glyph depends on something happening 16 codepoints onwards,
> or back, is extremely unlikely.
You are wrong. Please read this:
https://lists.freedesktop.org/archives/harfbuzz/2020-May/007517.html
https://lists.freedesktop.org/archives/harfbuzz/2020-May/007521.html
This is what is needed for doing ligatures The Right Way. Collecting
an arbitrary number of codepoint doesn't cut it.
And in any case, I was talking about the need to look _backward_,
i.e. when the character that triggers the composition is not the first
one in the sequence of the characters to be composed. This is usually
needed as an optimization: if you have 2-character sequences where the
second character is one of a much smaller set than the first, then
using the second character as an anchor will use up less memory when
you set up composition-function-table. A case in point is a base
character and a diacritic.
How many characters you need _forward_ is an entirely different issue.
> It needs to be modified, significantly, to support entering glyphs, to
> support kerning, and to support things like ligating across a buffer
> text / display string boundary.
Two of these are not needed or are outright wrong, and the third
doesn't need anything, the shaper already does that with any text you
pass through it.
> But, seriously, you're still willing to argue that point shouldn't be
> able to enter the "ffi" glyph? Not even if the user wants it? Because
> if so, I suggest we interrupt the discussion here.
See above. I indeed see no reason to continue this discussion, as
evidently any progress here is impossible with your attitude in place.
^ permalink raw reply [flat|nested] 145+ messages in thread
end of thread, other threads:[~2020-05-27 19:19 UTC | newest]
Thread overview: 145+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-05-17 10:41 Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
2020-05-17 14:09 ` Arthur Miller
2020-05-17 14:30 ` Eli Zaretskii
2020-05-17 15:06 ` Arthur Miller
2020-05-17 15:56 ` Eli Zaretskii
2020-05-17 16:50 ` Arthur Miller
2020-05-17 17:06 ` Eli Zaretskii
2020-05-17 14:35 ` Eli Zaretskii
2020-05-17 14:59 ` Julius Pfrommer
2020-05-17 15:55 ` Eli Zaretskii
2020-05-17 16:28 ` Pip Cet
2020-05-17 17:00 ` Eli Zaretskii
2020-05-17 18:50 ` Pip Cet
2020-05-17 19:17 ` Eli Zaretskii
2020-05-18 16:08 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
2020-05-18 16:45 ` tomas
2020-05-18 16:49 ` Eli Zaretskii
2020-05-18 17:05 ` Ligatures Stefan Monnier
2020-05-18 17:18 ` Ligatures Eli Zaretskii
2020-05-18 19:19 ` Ligatures Pip Cet
2020-05-18 19:25 ` Ligatures tomas
2020-05-18 19:41 ` Ligatures Pip Cet
2020-05-18 20:20 ` Ligatures tomas
2020-05-18 19:33 ` Ligatures Eli Zaretskii
2020-05-18 19:44 ` Ligatures Clément Pit-Claudel
2020-05-19 2:25 ` Ligatures Eli Zaretskii
2020-05-19 2:44 ` Ligatures Clément Pit-Claudel
2020-05-19 13:59 ` Ligatures Eli Zaretskii
2020-05-19 14:35 ` Ligatures Clément Pit-Claudel
2020-05-19 15:21 ` Ligatures Eli Zaretskii
2020-05-19 15:44 ` Ligatures Clément Pit-Claudel
2020-05-19 16:15 ` Ligatures Eli Zaretskii
2020-05-19 15:36 ` Ligatures Tassilo Horn
2020-05-19 16:08 ` Ligatures Eli Zaretskii
2020-05-19 16:14 ` Ligatures Stefan Monnier
2020-05-19 3:47 ` Ligatures Stefan Monnier
2020-05-19 4:51 ` Ligatures Clément Pit-Claudel
2020-05-18 19:38 ` Ligatures Clément Pit-Claudel
2020-05-19 14:55 ` Ligatures Pip Cet
2020-05-19 15:30 ` Ligatures Clément Pit-Claudel
2020-05-19 15:52 ` Ligatures Pip Cet
2020-05-18 17:24 ` Ligatures tomas
2020-05-18 17:41 ` Ligatures Eli Zaretskii
2020-05-18 19:07 ` Ligatures tomas
2020-05-18 19:17 ` Ligatures Eli Zaretskii
2020-05-18 20:33 ` Ligatures Stefan Monnier
2020-05-18 17:31 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Clément Pit-Claudel
2020-05-18 17:39 ` Eli Zaretskii
2020-05-18 19:01 ` Clément Pit-Claudel
2020-05-18 19:15 ` Eli Zaretskii
2020-05-18 19:18 ` tomas
2020-05-18 20:37 ` Ligatures Stefan Monnier
2020-05-18 21:59 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Alan Third
2020-05-19 13:56 ` Eli Zaretskii
2020-05-19 14:39 ` Clément Pit-Claudel
2020-05-19 21:43 ` Pip Cet
2020-05-20 1:41 ` Clément Pit-Claudel
2020-05-20 2:07 ` Ligatures Stefan Monnier
2020-05-20 7:14 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) tomas
2020-05-20 15:18 ` Eli Zaretskii
2020-05-20 17:31 ` Clément Pit-Claudel
2020-05-20 18:01 ` Eli Zaretskii
2020-05-20 18:33 ` Clément Pit-Claudel
2020-05-20 18:49 ` Eli Zaretskii
2020-05-20 18:53 ` Clément Pit-Claudel
2020-05-20 19:02 ` Eli Zaretskii
2020-05-20 23:19 ` Ligatures Stefan Monnier
2020-05-21 10:01 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Pip Cet
2020-05-21 14:11 ` Eli Zaretskii
2020-05-21 16:26 ` Pip Cet
2020-05-21 19:08 ` Eli Zaretskii
2020-05-21 20:51 ` Clément Pit-Claudel
2020-05-21 21:16 ` Pip Cet
2020-05-22 6:12 ` Eli Zaretskii
2020-05-22 9:25 ` Pip Cet
2020-05-22 11:23 ` Eli Zaretskii
2020-05-22 12:52 ` Pip Cet
2020-05-22 13:15 ` Eli Zaretskii
2020-05-22 13:29 ` Clément Pit-Claudel
2020-05-22 14:30 ` Eli Zaretskii
2020-05-22 14:34 ` Clément Pit-Claudel
2020-05-22 19:01 ` Eli Zaretskii
2020-05-22 19:33 ` Clément Pit-Claudel
2020-05-22 19:44 ` Eli Zaretskii
2020-05-22 20:02 ` Clément Pit-Claudel
[not found] ` <83mu5z171j.fsf@gnu.org>
2020-05-23 14:34 ` Clément Pit-Claudel
2020-05-23 16:18 ` Eli Zaretskii
2020-05-23 16:37 ` Clément Pit-Claudel
2020-05-22 13:56 ` Pip Cet
[not found] ` <83lflj16jn.fsf@gnu.org>
[not found] ` <AF222EA0-FE05-4224-8459-2BF82CE27266@vasilij.de>
[not found] ` <834ks7110w.fsf@gnu.org>
2020-05-23 11:24 ` Vasilij Schneidermann
2020-05-23 13:04 ` Eli Zaretskii
[not found] ` <83eerb145r.fsf@gnu.org>
[not found] ` <CAOqdjBeef8Fa596raEyBUwv0Zr+41LSiYvHW39EdoaXpyxCXVw@mail.gmail.com>
[not found] ` <831rnb0zld.fsf@gnu.org>
2020-05-23 12:36 ` Pip Cet
2020-05-23 14:08 ` Eli Zaretskii
2020-05-23 15:13 ` Pip Cet
2020-05-23 16:34 ` Eli Zaretskii
2020-05-23 22:38 ` Pip Cet
2020-05-24 15:33 ` Eli Zaretskii
2020-05-26 18:13 ` Pip Cet
2020-05-26 19:46 ` Eli Zaretskii
2020-05-27 9:36 ` Pip Cet
2020-05-27 17:13 ` Eli Zaretskii
2020-05-27 18:42 ` Pip Cet
2020-05-27 19:19 ` Eli Zaretskii
2020-05-23 17:32 ` Eli Zaretskii
2020-05-23 21:29 ` Pip Cet
2020-05-24 15:19 ` Eli Zaretskii
2020-05-23 12:47 ` Ligatures Stefan Monnier
2020-05-23 13:10 ` Ligatures Eli Zaretskii
2020-05-23 13:45 ` Ligatures Stefan Monnier
2020-05-23 14:12 ` Ligatures Eli Zaretskii
2020-05-23 13:36 ` Ligatures 조성빈
2020-05-23 14:15 ` Ligatures Stefan Monnier
2020-05-23 14:37 ` Ligatures Pip Cet
2020-05-22 11:44 ` Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Eli Zaretskii
2020-05-22 13:26 ` Clément Pit-Claudel
2020-05-22 14:29 ` Eli Zaretskii
2020-05-22 14:32 ` Clément Pit-Claudel
2020-05-22 19:00 ` Eli Zaretskii
2020-05-21 21:06 ` Pip Cet
2020-05-22 6:06 ` Eli Zaretskii
2020-05-22 9:34 ` Pip Cet
2020-05-22 11:33 ` Eli Zaretskii
2020-05-19 20:26 ` Alan Third
2020-05-19 10:09 ` Trevor Spiteri
2020-05-19 14:22 ` Eli Zaretskii
2020-05-19 5:43 ` Ligatures ASSI
2020-05-19 7:22 ` Ligatures tomas
2020-05-19 7:55 ` Ligatures Joost Kremers
2020-05-19 8:07 ` Ligatures tomas
2020-05-19 10:17 ` Ligatures Yuri Khan
2020-05-19 14:26 ` Ligatures Eli Zaretskii
2020-05-19 19:00 ` Ligatures Yuri Khan
2020-05-19 10:43 ` Ligatures Werner LEMBERG
2020-05-19 10:48 ` Ligatures tomas
2020-05-19 14:18 ` Ligatures Eli Zaretskii
2020-05-19 14:52 ` Ligatures Eli Zaretskii
2020-05-19 15:11 ` Ligatures Pip Cet
2020-05-19 15:36 ` Ligatures Eli Zaretskii
2020-05-19 16:16 ` Ligatures Pip Cet
2020-05-19 16:41 ` Ligatures Eli Zaretskii
2020-05-19 17:00 ` Ligatures Eli Zaretskii
2020-05-17 18:28 ` Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY) Julius Pfrommer
2020-05-17 18:45 ` Eli Zaretskii
2020-05-17 22:28 ` chad
2020-05-18 22:08 ` Alan Third
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.