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

TextMetrics doesn't have an initial advance attribute #4030

Open
litherum opened this Issue Sep 12, 2018 · 12 comments

Comments

5 participants
@litherum

litherum commented Sep 12, 2018

There's a collection of advances, but no initial advance. The initial advance is used in complex scripts where the first glyph in the string has to draw before the origin.

@litherum

This comment has been minimized.

Show comment
Hide comment
@litherum

litherum commented Sep 12, 2018

@kojiishi

This comment has been minimized.

Show comment
Hide comment
@kojiishi

kojiishi Sep 13, 2018

Oh, it's a very good point.

Can I ask a clarification; is it the initial glyph advance, or the initial glyph offset? Our logic is like this:

  1. The layout engine has a current_pen_point.
  2. Each glyph is drawn at current_pen_point + glyph_offset.
  3. After each glyph is drawn, current_pen_point += glyph_advance.

So our logic handles the initial glyph positioning as an offset, and offsets are not accumulated to the advance. IIUC this is what OpenType has in its format, but I'm mostly seeing it through HarfBuzz API surface, so I might be wrong for other formats or platform APIs.


(Terminologies are old because the best picture I could find in OpenType spec was for TrueType 1.0)

If we were going to the initial advance model, I think we need how to compute it when the underlying API or format provides the initial offset but not the initial advance, whether it should be zero or it should be synthesized. If we were going with advances and offsets model, I think we need initialOffset member separately from advances, or it could even be offsets array. Probably offsets array is not useful unless we also provide glyph bounding box?

/cc @FremyCompany @dbaron @jfkthame @fserb @domenic @eaenet @whatwg/canvas

kojiishi commented Sep 13, 2018

Oh, it's a very good point.

Can I ask a clarification; is it the initial glyph advance, or the initial glyph offset? Our logic is like this:

  1. The layout engine has a current_pen_point.
  2. Each glyph is drawn at current_pen_point + glyph_offset.
  3. After each glyph is drawn, current_pen_point += glyph_advance.

So our logic handles the initial glyph positioning as an offset, and offsets are not accumulated to the advance. IIUC this is what OpenType has in its format, but I'm mostly seeing it through HarfBuzz API surface, so I might be wrong for other formats or platform APIs.


(Terminologies are old because the best picture I could find in OpenType spec was for TrueType 1.0)

If we were going to the initial advance model, I think we need how to compute it when the underlying API or format provides the initial offset but not the initial advance, whether it should be zero or it should be synthesized. If we were going with advances and offsets model, I think we need initialOffset member separately from advances, or it could even be offsets array. Probably offsets array is not useful unless we also provide glyph bounding box?

/cc @FremyCompany @dbaron @jfkthame @fserb @domenic @eaenet @whatwg/canvas

@litherum

This comment has been minimized.

Show comment
Hide comment
@litherum

litherum Sep 13, 2018

Right, that model is the same as the OpenType model. The good thing about that model is that it includes both visual information and layout information in a single place; the glyph_offset isn't used for layout, but is used for painting. The bad thing about that model is that it's pretty complicated to understand.

In WebKit, we use a slightly different model, where we completely separate paint information from layout information, and put the information into different data structures. Each data structure is just a flat array of advances. Layout information doesn't need an initial advance, but paint information does.

I made an ascii-art picture of it here inside the WebKit source: https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ComplexTextController.h#L108

In order to have rendering consistent with the browser, one or the other needs to be exposed. I assume that the advances exposed by this API are visual advances, not layout advances. I recommend the WebKit way because it's simpler to understand and use.

litherum commented Sep 13, 2018

Right, that model is the same as the OpenType model. The good thing about that model is that it includes both visual information and layout information in a single place; the glyph_offset isn't used for layout, but is used for painting. The bad thing about that model is that it's pretty complicated to understand.

In WebKit, we use a slightly different model, where we completely separate paint information from layout information, and put the information into different data structures. Each data structure is just a flat array of advances. Layout information doesn't need an initial advance, but paint information does.

I made an ascii-art picture of it here inside the WebKit source: https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ComplexTextController.h#L108

In order to have rendering consistent with the browser, one or the other needs to be exposed. I assume that the advances exposed by this API are visual advances, not layout advances. I recommend the WebKit way because it's simpler to understand and use.

@kojiishi

This comment has been minimized.

Show comment
Hide comment
@kojiishi

kojiishi Sep 13, 2018

Thank you, the ascii-chart looks great!! I understand the distinction much clearer.

In your terminology, I thought advances are about layout advance. We only have layout advance and use it to layout. As I wrote above, we have glyph offset too, but it's only for paint and computing glyph bounding boxes.

As I re-read the OpenType spec now, I found the spec for hmtx says:

In a font with CFF version 1 outline data, the 'CFF ' table does include advance widths. These values are used by PostScript processors, but are not used in OpenType layout. In an OpenType context, the 'hmtx' table is required and must be used for advance widths.

From this I'm guessing that paint advance is the one in CFF table and layout advance is the one in hmtx table, and TrueType has only layout advance?

kojiishi commented Sep 13, 2018

Thank you, the ascii-chart looks great!! I understand the distinction much clearer.

In your terminology, I thought advances are about layout advance. We only have layout advance and use it to layout. As I wrote above, we have glyph offset too, but it's only for paint and computing glyph bounding boxes.

As I re-read the OpenType spec now, I found the spec for hmtx says:

In a font with CFF version 1 outline data, the 'CFF ' table does include advance widths. These values are used by PostScript processors, but are not used in OpenType layout. In an OpenType context, the 'hmtx' table is required and must be used for advance widths.

From this I'm guessing that paint advance is the one in CFF table and layout advance is the one in hmtx table, and TrueType has only layout advance?

@litherum

This comment has been minimized.

Show comment
Hide comment
@litherum

litherum Sep 13, 2018

From this I'm guessing that paint advance is the one in CFF table and layout advance is the one in hmtx table, and TrueType has only layout advance?

Nope, that's not right. A font where CFF disagrees with hmtx is a broken font. (I learned this the hard way...)

The offsets come from the GPOS table. You only get them if you have font features.

litherum commented Sep 13, 2018

From this I'm guessing that paint advance is the one in CFF table and layout advance is the one in hmtx table, and TrueType has only layout advance?

Nope, that's not right. A font where CFF disagrees with hmtx is a broken font. (I learned this the hard way...)

The offsets come from the GPOS table. You only get them if you have font features.

@litherum

This comment has been minimized.

Show comment
Hide comment
@litherum

litherum Sep 13, 2018

This type of confusion that you had is exactly the reason that a flat set of advances is a better API than a hybrid advance/offset combination.

Originally, transforming the data into a flat list of paint advances was required for us because it's the interface to the text drawing routine we used. Now, it's no longer required because we switched to one that accepts positions instead of advances, but the argument still holds. Either way, the "two separate flat lists" approach doesn't require diagrams, but the hybrid advance/offset does.

litherum commented Sep 13, 2018

This type of confusion that you had is exactly the reason that a flat set of advances is a better API than a hybrid advance/offset combination.

Originally, transforming the data into a flat list of paint advances was required for us because it's the interface to the text drawing routine we used. Now, it's no longer required because we switched to one that accepts positions instead of advances, but the argument still holds. Either way, the "two separate flat lists" approach doesn't require diagrams, but the hybrid advance/offset does.

@litherum

This comment has been minimized.

Show comment
Hide comment
@litherum

litherum Sep 13, 2018

It would definitely be a mistake for this API to produce layout advances because this is a canvas API, which is presumably used for drawing things. If clients use this API to draw characters, the characters would all end up at the wrong place.

litherum commented Sep 13, 2018

It would definitely be a mistake for this API to produce layout advances because this is a canvas API, which is presumably used for drawing things. If clients use this API to draw characters, the characters would all end up at the wrong place.

@kojiishi

This comment has been minimized.

Show comment
Hide comment
@kojiishi

kojiishi Sep 13, 2018

Thank you for the explanation. It clarifies that I didn't understand the differences between the two correctly, please give me some time to learn further.

In the meantime, allow me to comment that we would like this API and Houdini Font Metrics API as much compatible as possible, or even unify if possible. So great if we can try to cover the use cases both for canvas and for the layout purposes. I hope this goal is good to us all.

kojiishi commented Sep 13, 2018

Thank you for the explanation. It clarifies that I didn't understand the differences between the two correctly, please give me some time to learn further.

In the meantime, allow me to comment that we would like this API and Houdini Font Metrics API as much compatible as possible, or even unify if possible. So great if we can try to cover the use cases both for canvas and for the layout purposes. I hope this goal is good to us all.

@jfkthame

This comment has been minimized.

Show comment
Hide comment
@jfkthame

jfkthame Sep 13, 2018

It would definitely be a mistake for this API to produce layout advances because this is a canvas API, which is presumably used for drawing things.

I think this API is confused, and doesn't adequately address the character/glyph model of text rendering. (See #4026.) If "this is a canvas API ... used for drawing", it should work in terms of the things that are actually drawn to the canvas, which are glyphs, not characters.

If clients use this API to draw characters, the characters would all end up at the wrong place.

So how are clients going to use this API to do anything useful, except in simple cases where there's basically a 1:1 character/glyph mapping?

jfkthame commented Sep 13, 2018

It would definitely be a mistake for this API to produce layout advances because this is a canvas API, which is presumably used for drawing things.

I think this API is confused, and doesn't adequately address the character/glyph model of text rendering. (See #4026.) If "this is a canvas API ... used for drawing", it should work in terms of the things that are actually drawn to the canvas, which are glyphs, not characters.

If clients use this API to draw characters, the characters would all end up at the wrong place.

So how are clients going to use this API to do anything useful, except in simple cases where there's basically a 1:1 character/glyph mapping?

@litherum

This comment has been minimized.

Show comment
Hide comment
@litherum

litherum Sep 13, 2018

I think this API is confused

I think you're right. These discussions we're having would benefit from some use cases.

litherum commented Sep 13, 2018

I think this API is confused

I think you're right. These discussions we're having would benefit from some use cases.

@litherum

This comment has been minimized.

Show comment
Hide comment
@litherum

litherum Sep 14, 2018

In the meantime, allow me to comment that we would like this API and Houdini Font Metrics API as much compatible as possible, or even unify if possible.

+1

litherum commented Sep 14, 2018

In the meantime, allow me to comment that we would like this API and Houdini Font Metrics API as much compatible as possible, or even unify if possible.

+1

domenic added a commit that referenced this issue Sep 14, 2018

Revert "Add advances to TextMetrics and change baselines API"
This reverts commit 7711a1f. As
discussed in #3995, these changes were made prematurely without
appropriate implementer signoff. Since then, a plethora of issues around
the changes here have been opened up (e.g. #3994, #4023, #4030, #4033,
#4034). We revert these changes until a more complete and agreed-upon
specification can replace them.

Closes #3995.

domenic added a commit that referenced this issue Sep 17, 2018

Revert "Add advances to TextMetrics and change baselines API"
This reverts commit 7711a1f. As
discussed in #3995, these changes were made prematurely without
appropriate implementer sign-off. Since then, a plethora of issues
around the changes here have been opened up (e.g. #3994, #4023, #4026,
#4030, #4033, #4034). We revert these changes until a more complete and
agreed-upon specification can replace them.

Closes #3995.
@behdad

This comment has been minimized.

Show comment
Hide comment
@behdad

behdad Sep 20, 2018

The API is based on characters, not glyphs, so this issue is completely moot to begin with.

behdad commented Sep 20, 2018

The API is based on characters, not glyphs, so this issue is completely moot to begin with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment