Code Monkey home page Code Monkey logo

Comments (12)

kiliman avatar kiliman commented on July 29, 2024 5

I've been reading up on how contextual substitutions work in OpenType as well as how it's used in Fira Code. I think I understand it much better now. I'm working on an experimental font with a few ligatures for testing.

Here's an animation of how the spacing works.

ligature-spacing-test

Here's how the glyph is created.

image

Notice the negative LSB (Left Side Bearing). The way Fira Code works is that instead of substituting equal + equal into a single double-wide glyph equal_equal.liga like I currently do, it actually uses 2 glyphs, one name LIG which is simply a single width glyph with no visual representation, plus the equal_equal.liga with negative LSB.

So basically LIG advances one character width, then the ligature moves back to the left with the negative LSB. The editor and terminal think there are two characters and the caret is displayed properly.

Pretty clever, but makes it a little trickier to design the glyphs because you have to calculate the proper LSB. The actual contextual substitution lookups are really nasty and will have to programmatically generated. I'm working on that now.

from operator-mono-lig.

kiliman avatar kiliman commented on July 29, 2024 3

I have a working version of the font in VS Code that supports both caret positioning and chained ligatures (#37).

Here's an example:

ligature-contextual-substitution

Now to redo all the ligatures 😣 ... I can see the finish line 🏁

from operator-mono-lig.

kiliman avatar kiliman commented on July 29, 2024 1

I'm almost done with the first set of ligatures. I even included some extra ones for fun.

image

from operator-mono-lig.

kiliman avatar kiliman commented on July 29, 2024 1

@dannymcgee The book is Fonts & Encodings by Yannis Haralambous[1]

Appendix D.9 The OpenType Advanced Typographic Tables (along with a bunch of trial and error) is where I got most of the info.

If you look at the gsub.js file[2] you'll see how I build up the lookup tables. I also talk about it in this comment[3].

I would also recommend this tool: OTMaster Light[4] from Dutch Type Library. It was invaluable in making sure my code was generating the correct tables.

Here's an example showing how the => ligature is rendered. It has checks for repeating characters (so multiple chains of == doesn't render the wrong glyph. Also adds LIG glyphs to support carets inside the ligature glyph.

subst-sample2

[1] https://www.amazon.com/Fonts-Encodings-Advanced-Typography-Everything/dp/0596102429
[2] https://github.com/kiliman/operator-mono-lig/blob/features/contextsubst/gsub.js
[3] #37 (comment)
[4] https://www.fontmaster.nl/index.php/test-demo/

from operator-mono-lig.

kiliman avatar kiliman commented on July 29, 2024 1

BTW: I only had to dig through all this mess because I couldn't distribute the ligature versions of the fonts directly.

You can use a font editor like Font Forge or Glyphs to generate the tables for you. Here's the script the FiraCode uses to generated the calt tables.

https://github.com/tonsky/FiraCode/blob/master/clojure/regen_calt.clj

from operator-mono-lig.

kiliman avatar kiliman commented on July 29, 2024

Yes, I agree. I did try to replicate the way Fira Code does it, but was not successful. I'm not sure what trick they used. I noticed they used negative LSB, but they also must include some spacing rules.

I'm not an expert on OpenType, so this is the best I could come up with. Perhaps someone with more experience could point me in the right direction.

Other than that, I hope you're enjoying the ligatures.

Thanks!

from operator-mono-lig.

chrilith avatar chrilith commented on July 29, 2024

You did and still do a great job on that ;)

let's wait to see if someone can help on this!

from operator-mono-lig.

wez avatar wez commented on July 29, 2024

in kovidgoyal/kitty#182 I'm trying to make the ligatures in this font render in the kitty terminal emulator. From the discussion there it sounds like Fira Code uses dummy blank glyphs. Not sure how/if that helps your figure this out.

from operator-mono-lig.

kiliman avatar kiliman commented on July 29, 2024

This has been pushed to the features/contextsubst branch.

from operator-mono-lig.

jabacchetta avatar jabacchetta commented on July 29, 2024

@kiliman Are the steps still the same for this branch? The master branch worked fine, but the build script in the features/contextsubst branch doesn't appear to be doing anything for me. I'll have to dig deeper when I get the free time.

Might be worthwhile adding a note about this feature in the documentation as well. I just assumed this wasn't possible until I noticed it existed in Fira Code, which led me to this issue.

Appreciate your work on this!

from operator-mono-lig.

kiliman avatar kiliman commented on July 29, 2024

@jabacchetta currently only the Operator Mono SSm Book and Operator Mono Light (partial) work in the features/contextsubst branch. In order to support these features, the ligatures have to be redone.

If you look at the comment above #35 (comment)

You'll see that all the glyphs have to be shifted left with negative left bearing. The original way was to have a character that was 2-3 glyphs wide. So => would be 1250 wide vs 625 for a single glyph.

The new way makes all the ligatures 625 wide, but the extra stuff is shifted to the left. When it is rendered, it actually renders an invisible character LIG followed by the ligature.

So => would be LIG + (=> glyph)... the LIG would advance 625, then the ligature glyph (due to negative left bearing) would actually start rendering over top of the invisible LIG. This is how you get the caret positioning.

Hope that makes sense. I literally had to buy a book on OpenType fonts in order to understand it.

from operator-mono-lig.

dannymcgee avatar dannymcgee commented on July 29, 2024

Hey @kiliman, would you be willing to share what book you bought and which chapters/sections were relevant for figuring out this issue? I'm trying to make my own original typeface with coding ligatures, and I'm having a hell of a time trying to figure out the maze of substitution/lookup rules to make this work.

from operator-mono-lig.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.