From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Pip Cet Newsgroups: gmane.emacs.devel Subject: Re: Ligatures (was: Unify the Platforms: Cairo+FreeType+Harfbuzz Everywhere (except TTY)) Date: Thu, 21 May 2020 16:26:13 +0000 Message-ID: References: <20200517165953.000044d2@web.de> <83lflqblp0.fsf@gnu.org> <83ftbybio3.fsf@gnu.org> <83zha69xs2.fsf@gnu.org> <83367x9qeq.fsf@gnu.org> <0ccae2a4-533b-d15c-2884-c2f00b067776@gmail.com> <83wo5987mk.fsf@gnu.org> <99d4beed-88ae-b5cd-3ecb-a44325c8a1dc@gmail.com> <20200518215908.GA57594@breton.holly.idiocy.org> <83mu6481v3.fsf@gnu.org> <75a90563-51b4-d3b8-4832-fc0e2542af0d@gmail.com> <83blmi7hys.fsf@gnu.org> <837dx55qff.fsf@gnu.org> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="17411"; mail-complaints-to="usenet@ciao.gmane.io" Cc: cpitclaudel@gmail.com, alan@idiocy.org, emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Thu May 21 18:27:27 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jbo2Z-0004On-7H for ged-emacs-devel@m.gmane-mx.org; Thu, 21 May 2020 18:27:27 +0200 Original-Received: from localhost ([::1]:33418 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jbo2Y-0002ac-9c for ged-emacs-devel@m.gmane-mx.org; Thu, 21 May 2020 12:27:26 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:47934) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jbo21-0001rq-IW for emacs-devel@gnu.org; Thu, 21 May 2020 12:26:53 -0400 Original-Received: from mail-oi1-x232.google.com ([2607:f8b0:4864:20::232]:43482) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jbo20-0002YW-80; Thu, 21 May 2020 12:26:53 -0400 Original-Received: by mail-oi1-x232.google.com with SMTP id i22so6680766oik.10; Thu, 21 May 2020 09:26:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=h7UXvHdIcY4Ge6LUCOHyM/oG85e9CGXSg48fqvSlZTs=; b=tVtH0jXi5b/5iJ8oLZi/bW1q9sXJ23M/SC0rqr89ovC27iDEMFipZFpgAuf+MTor8f ATbwRztZxnSLfCqkvip9rwu3jG03eKoV5pHKFGH6u2CnGhy45B1AJQ2Yaxz+gaS+vZHn OQ3lYE6vQGvdwg1tq+1BQ+31ZuwH76n7K3zQ0PrR0MRCK0hMg43VXxOu6+mk2tSChUXX FjdJMqXZronru7GX8G/rZgwKVhTYsXDrVRLIkoQMftZzYFPyUifBLewP5cW747KnLnpm Qcl6Y6YjHfchENwc2nCaSc6VX6L/T9JZ7l96BmKEZnie4DaZTle31P53h/sJ/lMgMJJQ mKjg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=h7UXvHdIcY4Ge6LUCOHyM/oG85e9CGXSg48fqvSlZTs=; b=b4d4AXL9Bvdi0kHmcMG98v4JGh+T+7w6lS3rnVYDRfGM9SSWzCkD0NRrbg5f3ydFfd MrbYTGmqvwRDfT+HfuTGgai7rZTFVd/2QSHLK5BVT1ox77NGkcjjC8fw6On+Bz7CsrHk U1Ak/LHNytmpSi4GLUoyS9b/5ylwZr0Xo3UXVKw+2alQxpZFqMLQbFY/zs1+lpjkBjsC kISQ1/WFRkCgE0PKrp9rMKAw/gUiuh/z2U1+4XOXffLrOGnmm6l+BnhUBFAAT8uTp6Bw LiCXVJg9uaO38UMKG3g43HIwUQAUHuFLC34N8p0Zo/WVi+Gg5PpcLHMSBG6bTTDQmjAa b31g== X-Gm-Message-State: AOAM531uQzoYmMlnPRJIFLnDHobhD/l1eADQnq+SIIToT6+9EB7pjFul HwP5HQk4+nr7r3TEOwmKl9qqUOxOCNnEdRPMuPeh822G X-Google-Smtp-Source: ABdhPJyjOoPIEKK+8KJdZhUlkNo7FyW1e9ep+ieDQzmdyCVOBaxJXQMJ+XdHdADY6EsL5Qrofk/5TMhkLyhEa3K/vtM= X-Received: by 2002:aca:6705:: with SMTP id z5mr7020795oix.122.1590078410308; Thu, 21 May 2020 09:26:50 -0700 (PDT) In-Reply-To: <837dx55qff.fsf@gnu.org> Received-SPF: pass client-ip=2607:f8b0:4864:20::232; envelope-from=pipcet@gmail.com; helo=mail-oi1-x232.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, FREEMAIL_REPLY=1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:251175 Archived-At: On Thu, May 21, 2020 at 2:11 PM Eli Zaretskii wrote: > > From: Pip Cet > > 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.