Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"OpenType Classic" and multiple concurrent versions #780

Closed
davelab6 opened this issue Jun 1, 2021 · 15 comments
Closed

"OpenType Classic" and multiple concurrent versions #780

davelab6 opened this issue Jun 1, 2021 · 15 comments
Assignees
Milestone

Comments

@davelab6
Copy link

davelab6 commented Jun 1, 2021

A few months ago, the folks commissioned by Google to onboard fonts and write fontbakery linter checks for fonts discussed that nested truetype components are not correctly rendered by many PostScript based printers (eg a nice one from Xerox) and some other software that is not compliant with the spec (fonttools/fontbakery#2961)

In the fontbakery project, we aim to have good rationale statements to explain why checks are the way they are; https://github.com/googlefonts/fontbakery/pull/3082/files explains in more detail why Google Fonts is no longer accepting fonts with nested components, and at fonttools/fontbakery#3181 I posted some longer term thinking about how GF could do better than simply flattening all components.

However, I now understand that, for a long time, MS fonts have shipped with nested components. It seems updating "the" OpenType spec to recommend against nested components would be unlikely, since the MS implementations handle this correctly for a long time.

Still, it does make sense to me that PS based systems don't handle them even today, as they are really translating TT fonts into PS fonts on the fly, and often have other bugs related to that process... such bugs were so notorious when I was a student 20 years ago that I was taught "TTFs are not for print, only Type1," but they have all got a lot better since then.

I remember the way CSS 2.1 and 3 went, where the bits of CSS 2 that never shipped were dropped from 2.1, and most were reintroduced in 3. For fonts, since OT 1.8.4 isn't fully implemented everywhere, the burgeoning 1.9 will push that further, and subsequent releases will go further and further from shipped/stranded implementations (in printers and old software that people won't upgrade), we are going to end up with a more heterogeneous world for sure.

So, I would like to propose an "OpenType Classic" that essentially does what CSS2.1 did, and does update the spec, to clearly explain what really has been implemented absolutely everywhere, so people can make fonts to that format standard, as well as other (newer) ones.

Of course, fontbakery can offer such a check profile that is "overly strict" in this way, and there's no strong need for OpenType to do this... But, if the spec evolves in the next few years, with changes that are not suitable for incrementing the patch or minor versions in the semver model, it might be best to "evolve backwards" as well as forwards :)

(In many ways, I am repeating what Adam Twardoch wrote many years ago, at
https://lists.w3.org/Archives/Public/public-webfonts-wg/2013Jun/0027.html)

@tiroj
Copy link

tiroj commented Jun 1, 2021

However, I now understand that, for a long time, MS fonts have shipped with nested components.

Do you have a list of such fonts from MS? In the fonts we’ve made for them, we have avoided any nested components and also any scaled or flipped components, even though the spec allows for such things, because they were known to cause problems in some environments.

We recently discovered that some nested components had snuck into Sitka due to a change in the toolchain for some revisions, and have been removing those after consultation with MS.

[Coincidentally, you find me this afternoon fixing sources from another designer that used flipped components for /questiondown/ and /exclamdown/—particularly annoying when they are also used, offset, for .case variants.]

@tiroj
Copy link

tiroj commented Jun 1, 2021

On the broader subject: I always liked Adam’s idea of tailored OT subset specs. As I recall, the parallel was to things like colour space standards for PDF output, suggesting that one could use export filters in a font tool to target specific environments or uses. In fact, we already do this by setting up export profiles in our tools and options in our build scripts, but these are based on local understanding, informally shared information, or prayer, and having them standardised somewhere—by which I mean subject to a standards process, not just documented by someone e.g. in FontBakery—would be great.

@moyogo
Copy link

moyogo commented Jun 2, 2021

Here is the list of MS Windows 10 build 19041 fonts and their nested components glyphs:

  • ArialNova-Bold.ttf: uni0189
  • ArialNova-BoldItalic.ttf: uni0189
  • GeorgiaPro-LightItalic.ttf: uni0457
  • YuGothB.ttc: glyph24380
  • YuGothM.ttc: glyph24243
  • arial.ttf: Aringacute, aringacute, uni04EC, uni04ED, uniFCF2, uniFCF4
  • arialbd.ttf: Aringacute, glyph01353, glyph01449, glyph01450, glyph01451, glyph01589, glyph01629, glyph01630, glyph01631, glyph03734, glyph03759, glyph03764, glyph03830, glyph03834, glyph03838, glyph04025, uni0678, uni069C, uni06C0, uni06CE, uni06D0, uni06D1, uni06FA, uni0775, uni0776, uni0777, uniFBA6, uniFCF2, uniFCF4
  • arialbi.ttf: Aringacute, Iotadieresis, Upsilondieresis, aringacute, glyph02428, glyph02429, glyph02430, glyph02431, glyph02432, glyph02433, glyph02434, glyph02435, glyph02444, glyph02445, glyph02446, glyph02447, iotadieresis, iotadieresistonos, iotatonos, omicrontonos, uni0189, uni02BA, uni0401, uni0407, uni0451, uni045D, uni045E, uni04E3, uni04E5, uni1F30, uni1F31, uni1F32, uni1F33, uni1F34, uni1F35, uni1F36, uni1F37, uni1F76, uni1F77, uni1FD0, uni1FD1, uni1FD2, uni1FD3, uni1FD6, uni1FD7
  • ariali.ttf: Aringacute, aringacute, uni02BA, uni03D3, uni045D, uni04E3, uni04E5, uni2034
  • bahnschrift.ttf: Alphatonos, Dcroat, Epsilontonos, Etatonos, Iotadieresis, Iotatonos, Omegatonos, Omicrontonos, Upsilondieresis, Upsilontonos, alphatonos, epsilontonos, etatonos, glyph00846, glyph00847, iotatonos, omegatonos, omicrontonos, uni0189, uni0259, uni02C9, uni037D, uni037E, uni03D3, uni03FE, uni03FF, uni0400, uni0401, uni040E, uni0419, uni0439, uni0450, uni0451, uni045E, uni0478, uni0479, uni04A2, uni04AC, uni04B2, uni04B3, uni04C1, uni04C2, uni04CF, uni04D0, uni04D1, uni04D2, uni04D3, uni04D6, uni04D7, uni04E6, uni04E7, uni04EF, uni04F1, uni04F3, uni1EE8, uni1EE9, uni1EEA, uni1EEB, uni1EEC, uni1EED, uni1EEE, uni1EEF, uni1EF0, uni1EF1, uni2236, upsilontonos
  • comic.ttf: glyph00925, glyph00965, glyph00989
  • comicbd.ttf: glyph00989
  • cour.ttf: epsilontonos, etatonos, glyph01035, glyph01038, glyph01061, glyph01064, glyph01090, glyph01486, glyph01487, glyph01494, glyph01495, iotatonos, omegatonos, omicrontonos, uni0407, uni04EC, uni04ED, uniFBD5, uniFBD6, upsilontonos
  • courbd.ttf: Aringacute, aringacute, glyph01486, glyph01487, glyph01494, glyph01495, glyph02986, glyph02990, glyph02995, glyph02996, glyph03003, glyph03004, uni04EC, uni04ED, uniFBD5, uniFBD6
  • couri.ttf: Aringacute, aringacute, uni1FD3, uni1FE3
  • dokchamp.ttf: onehalf, onequarter, threequarters
  • gadugib.ttf: uni01EC, uni01ED
  • gautamib.ttf: glyph00865
  • msjh.ttc: glyph28999, glyph29205, glyph29206, glyph29207, glyph29208, glyph29209, glyph29210, glyph29211, glyph29212, glyph29213, glyph29214, glyph29215, glyph29216, glyph29217, glyph29218
  • msjhbd.ttc: anoteleia
  • msuighub.ttf: glyph01060, uniFDF2
  • msuighur.ttf: glyph01060, uniFDF2
  • msyh.ttc: glyph29339, glyph29340, glyph29341, glyph29342, glyph29343, glyph29344, glyph29345, glyph29346, glyph29347, glyph29348, glyph29349, glyph29350, glyph29351, glyph29352, uni0403
  • msyhbd.ttc: anoteleia
  • msyhl.ttc: glyph29376, glyph29379, glyph29382, glyph29385, glyph29388, glyph29449, glyph29452, glyph29455, glyph29458, glyph29461
  • palai.ttf: Beta, Kappa, Omegatonos, glyph00881, uni0450, uni04D1, uni04D7, uni1EA4, uni1EA5, uni1EA6, uni1EA8, uni1EA9, uni1EAB, uni1F68, uni1F69, uni1F6A, uni1F6B, uni1F6C, uni1F6D, uni1F6E, uni1F6F, uni1FA8, uni1FA9, uni1FAA, uni1FAB, uni1FAC, uni1FAD, uni1FAE, uni1FAF, uni1FFA, uni1FFC
  • seguibli.ttf: uni040C
  • seguisb.ttf: glyph02455, uni0320, uni045C
  • shruti.ttf: glyph00432, glyph00436, glyph00437, glyph00438, glyph00439, glyph00440, glyph00443, glyph00444, glyph00446, glyph00448, glyph00449, glyph00454, glyph00455, glyph00456, glyph00486, glyph00490, glyph00491, glyph00492, glyph00493, glyph00494, glyph00497, glyph00498, glyph00500, glyph00756, glyph00833, glyph00915, glyph00919, glyph00920, glyph00921, glyph00922, glyph00923, glyph00926, glyph00927, glyph00929
  • sylfaen.ttf: uni045E
  • tahoma.ttf: glyph01418, glyph01419, glyph01426, glyph01427, uniFBD5, uniFBD6
  • tahomabd.ttf: glyph01418, glyph01419, glyph01426, glyph01427, uniFBD5, uniFBD6
  • times.ttf: Aringacute, aringacute, uni04EC, uni04ED
  • timesbd.ttf: Aringacute, aringacute, glyph01353, glyph01589, glyph03733, glyph03737, glyph03741, glyph04664, uni04EC, uni04ED, uni0678, uni06C0, uni06CE, uni06D0, uni06D1, uni0775, uni0776, uni0777, uni1D63, uniFBA6
  • timesbi.ttf: Aringacute, aringacute, glyph02411, glyph02412, glyph02413, glyph02414, glyph02415, glyph02416, glyph02417, glyph02418, glyph02427, glyph02428, glyph02429, glyph02430, uni04E3, uni04E5, uni1F30, uni1F31, uni1F32, uni1F33, uni1F34, uni1F35, uni1F36, uni1F37, uni1F76, uni1F77, uni1FD0, uni1FD1, uni1FD2, uni1FD3, uni1FD6, uni1FD7
  • timesi.ttf: Aringacute, aringacute, glyph02411, glyph02412, glyph02413, glyph02414, glyph02415, glyph02416, glyph02417, glyph02418, glyph02427, glyph02428, glyph02429, glyph02430, uni03D3, uni04E3, uni04E5, uni1F30, uni1F31, uni1F32, uni1F33, uni1F34, uni1F35, uni1F36, uni1F37, uni1F76, uni1F77, uni1FD0, uni1FD1, uni1FD2, uni1FD3, uni1FD6, uni1FD7
  • tunga.ttf: glyph00327, glyph00332, glyph00350
  • tungab.ttf: glyph00360
  • vrindab.ttf: glyph00803

@tiroj
Copy link

tiroj commented Jun 2, 2021

Thanks, Denis. That is very interesting. Other than Bahnschrift—which I suspect is the only family on the list that was developed in Glyphs—those are old or very old fonts, and looking at which glyphs ended up as nested components, I suspect these may often be the byproduct of tools and carelessness—e.g. the /Beta/ in palai.ttf being a nested component of the Cyrillic Be rather than a straight component of the Latin B, as in the other fonts in that family—rather than planned.

This is one of the problems with nested components, on the development side: it is very easy in some tools to accidentally create nested components without actually realising that one is doing so. I have a request in to FontLab for a preference setting to never use nested components, because at the moment it will default to nesting when it can, and I suspect Glyphs might do likewise. [FLS5 never didn’t make nested components, which explains why there is a long period of MS fonts not containing nested components when that was the common development tool.]

@PeterCon
Copy link
Collaborator

... nested truetype components are not correctly rendered by many PostScript based printers ... and some other software...

It seems updating "the" OpenType spec to recommend against nested components would be unlikely

@davelab6 If you could open an issue on the 'glyf' table, a note can be added to mention that in that page. Or, alternately, this could be mentioned in the Recommendations page.

@PeterCon PeterCon self-assigned this Oct 22, 2021
@PeterCon
Copy link
Collaborator

I'm not sure about multiple concurrent versions (does that actually advance clarity and better interoperability)? But I do support steering things toward better interoperability.

Since (i) the OT spec currently doesn't say anything about nesting, but should; (ii) clearly it has been permitted since the beginning of TT (so can't be prohibited now); and (iii) also clearly it has long been an issue for broad interop; I propose adding the following in the 'glyf' chapter:

Composite glyphs may be nested within other composite glyphs—that is, a composite glyph parent can include other composite glyphs as child components. Thus, a composite glyph description is a directed graph. This graph must be acyclic, with every path through the graph leading to a simple glyph as a leaf node. There is no minimum nesting depth that must be supported. For fonts to be compatible with the widest range of implementations, nesting of composites should be avoided.

Note: Some PostScript devices (and possibly other implementations) do not correctly render glyphs that have nested composite descriptions. A composite glyph description that has nested composites can be flattened to reference only simple glyphs as child components. This can lose some benefits of de-duplication of information, but can still retain significant size-saving benefits as well as providing broader compatibility.

(In OFF, notes can mention things that are possible but cannot include requirements or recommendations. )

@davelab6
Copy link
Author

davelab6 commented Oct 22, 2021 via email

@PeterCon
Copy link
Collaborator

I'm not sure what it would look like to "reflect that honestly" or what it would gain.

@PeterCon
Copy link
Collaborator

PeterCon commented Nov 10, 2021

For OT 1.9, the following addition to the 'glyf' chapter related to this issue is proposed:

Composite glyphs may be nested within other composite glyphs—that is, a composite glyph parent can include other composite glyphs as child components. Thus, a composite glyph description is a directed graph. This graph must be acyclic, with every path through the graph leading to a simple glyph as a leaf node. The maxComponentDepth field in the 'maxp' table is set to indicate the maximum nesting depth across all composite glyphs in a font. There is no minimum nesting depth that must be supported. For fonts to be compatible with the widest range of implementations, nesting of composites should be avoided.

Note: Some PostScript devices (and possibly other implementations) do not correctly render glyphs that have nested composite descriptions. A composite glyph description that has nested composites can be flattened to reference only simple glyphs as child components. This can lose some benefits of de-duplication of information, but can still retain significant size-saving benefits as well as providing broader compatibility.

@PeterCon PeterCon added this to the OpenType 1.9 milestone Nov 10, 2021
@Lorp
Copy link

Lorp commented Nov 10, 2021

It would be useful to mention maxp.maxComponentDepth at this point.

@davelab6
Copy link
Author

davelab6 commented Nov 10, 2021 via email

@PeterCon
Copy link
Collaborator

@Lorp Thanks for the suggestion. I've added a sentence in the first paragraph shown in the earlier comment.

The maxComponentDepth field in the 'maxp' table is set to indicate the maximum nesting depth across all composite glyphs in a font.

@tiroj
Copy link

tiroj commented Nov 11, 2021

The note regarding compatibility is a good addition. I wonder if we have somewhere a similar note regarding composite transformations (scaling, flipping) which I see being used in a lot of sources now but which have long caused problems in software (such that MS always required we not use them in fonts for them)?

@PeterConstable
Copy link

@tiroj If you'd like to see something on that in a future OT version, please open an issue for the glyf chapter with background and suggestions.

@PeterCon
Copy link
Collaborator

PeterCon commented Dec 9, 2021

Addressed in OpenType 1.9. Closing.

@PeterCon PeterCon closed this as completed Dec 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants