Skip to content

[css-fonts-5] Add glyph scaling override descriptor to @font-face #6075

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

Closed
fantasai opened this issue Mar 4, 2021 · 17 comments · Fixed by #6108
Closed

[css-fonts-5] Add glyph scaling override descriptor to @font-face #6075

fantasai opened this issue Mar 4, 2021 · 17 comments · Fixed by #6108
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-fonts-5

Comments

@fantasai
Copy link
Collaborator

fantasai commented Mar 4, 2021

In #5983 (comment) @jfkthame wrote:

I think there should be a separate font-size-override that can apply a scale factor to the used font size; I suspect this would often be the better tool to use.

Using a scaling factor to make adjustments for font fallback would avoid some of the more problematic aspects of advance-override (breaking cursive/complex scripts, breaking typographic rhythm by adding uneven spacing, breaking alignment at the edges of paragraphs).

It also provides a long-needed feature--optically matching fonts when mixing font faces--by allowing per-font scaling adjustments at the author's discretion. font-size-adjust does this for certain bicameral scripts by using the ex-height metric, but that doesn't work more generally across writing systems as noted in #4540 .

The proposal would be to add a descriptor taking a percentage and effectively functions the same as font-size-adjust for a given scale factor. Details to consider [suggestions in brackets to match font-size-adjust]:

  • Effect on em units? [No effect on em.]
  • Effect on ch/ic/ex units? [These are supposed to match glyph metrics, so are affected.]
  • Effect on baseline table? [Scales the table.]
  • Effect on ascent/descent metrics? [Should scale them also.]
  • Effect on ascent-override/descent-override/etc.? [Scales with the scale factor.]
  • Allow separate vertical/horizontal scale factors? [No idea. We can start with one and see if independent axes are needed.]
@fantasai
Copy link
Collaborator Author

fantasai commented Mar 4, 2021

Possible names: glyph-scale-factor, font-size-adjust, glyph-size-adjust, size-adjust.

@jfkthame
Copy link
Contributor

jfkthame commented Mar 4, 2021

Thanks for filing this! Mostly agree with the suggested details above, with one doubt:

* Effect on `ascent-override`/`descent-override`/etc.? [Scales with the scale factor.]

Not sure about this one. ascent-override etc are not derived from the size of the glyphs, they're provided so that the author can override the metrics coming from the font and establish known line-spacing metrics that are not dependent on the specific font:

the corresponding metric value is resolved as the given percentage multiplied by the used font size

(from css-fonts 4.11. Default font metrics overriding).

In my understanding, the scale factor proposed here is not altering the "used font size". Given the simplest case of content like:

<div style="font: 20px MyFont">foo bar

the specified, computed and used font sizes are all 20px. If MyFont has both metrics overrides and a glyph scaling descriptor applied:

@font-face {
    font-family: MyFont;
    src: local("Arial");
    glyph-scale-factor: 90%;
    ascent-override: 90%;
    descent-override: 30%;
}

the resulting ascent and descent metrics, used to compute the line box, remain 18px (90% * 20px) and 6px (30% * 20px) respectively. The glyph scaling just applies to the glyph outlines themselves (so this rule is "shrinking" Arial by 10%) and to metrics that are based on their measurements (the glyph advances, units like ch and ex, the default line metrics like ascent/descent that are derived from the font) but it does not affect anything based on font-size, which is unchanged.

One result of this -- which I think is correct -- is that glyph-scale-factor (or whatever it's called) will normally affect ch, ex, etc for the font to which it is applied. But in the event that the browser cannot determine these values from the font, and falls back to default heuristics as provided in CSS Units & Values:

In the cases where it is impossible or impractical to determine the measure of the “0” glyph, it must be assumed to be 0.5em wide by 1em tall. Thus, the ch unit falls back to 0.5em in the general case, and to 1em when it would be typeset upright (i.e. writing-mode is vertical-rl or vertical-lr and text-orientation is upright).

the resulting unit is not affected by the scale factor.

@jfkthame
Copy link
Contributor

jfkthame commented Mar 4, 2021

One other question is how this interacts with optical sizing, for fonts that offer an opsz variation axis.

I think the right answer is that it does affect the automatic application of opsz, but I haven't thought this through in detail; perhaps there are implementation considerations that will make that trickier.

@xiaochengh
Copy link
Contributor

I generally agree with @jfkthame.

One subtle issue is that, what exactly is the value being overridden? It should not be the font-size property value, neither computed nor used, since they work at different levels and should better not have extra dependency.

It feels more like hacking the font matching algorithm that, when trying to find a face with font size, say, 24px, we instead return a face of a different font size, and use it for text layout as if it were 24px.

Is there a nice way to specify it?

@drott
Copy link
Collaborator

drott commented Mar 5, 2021

One subtle issue is that, what exactly is the value being overridden? It should not be the font-size property value, neither computed nor used, since they work at different levels and should better not have extra dependency.

My understanding is the intention is not to use a fully down- or upscaled font internally as that would affect the line height. As @jfkthame explains, ascent / descent would still be computed from font-size:, which I think makes sense (otherwise what's the difference to using a different font-size: to start with? So perhaps it can be described from an implementation perspective as splitting the internal font object used for retrieving metrics for line height (ascent, descent) in layout from the one that we use to actually perform inline layout with, that we shape with, and that we shape with. Or perhaps more simply put: Keep line height, ascent, descent, baseline computations based on font-size: and original metrics at font-size: (taking ascent-override etc. into account), but then inside the line, using a scaled font which will operate at the decreased/increased font-size for how it behaves in shaping (scaled advances, shorter/longer text run results) and how it draws (smaller, larger glyphs).

@jfkthame
Copy link
Contributor

jfkthame commented Mar 5, 2021

My understanding is the intention is not to use a fully down- or upscaled font internally as that would affect the line height. As @jfkthame explains, ascent / descent would still be computed from font-size:,

Not quite. To clarify, my position is that ascent-override etc would continue to be computed based on the font-size, without regard to any glyph-scale-factor in effect; so if these descriptors are used to control line height, the glyph scaling will have no effect. But if ascent etc are not overridden by descriptors, the font's normal metrics will be affected by the scale factor.

which I think makes sense (otherwise what's the difference to using a different font-size: to start with?

This is not like using a different font-size because it is associated with an individual font face, not with an element property. So within a single element, styled with a single font-size, there might be multiple font faces in use (each covering a different script, for example), each of which could have its own different glyph-scale-factor, designed to visually harmonize the different designs.

It's also not like using a different font-size because it does not affect the size of the em unit, etc.

So perhaps it can be described from an implementation perspective as splitting the internal font object used for retrieving metrics for line height (ascent, descent) in layout from the one that we use to actually perform inline layout with, that we shape with, and that we shape with. Or perhaps more simply put: Keep line height, ascent, descent, baseline computations based on font-size: and original metrics at font-size: (taking ascent-override etc. into account),

As described above, I think that if the font is being queried for its normal ascent, descent, baseline, etc., these metrics should come from the scaled font so that they maintain their expected relationship with the glyph shapes. It's in the case when override descriptors are used to set them to specific values (expressed as percentages of font-size) that the scaling has no effect; an ascent of 80%, for instance, should remain at 80% of 1em regardless of the scaling of the glyphs relative to the em-square.

but then inside the line, using a scaled font which will operate at the decreased/increased font-size for how it behaves in shaping (scaled advances, shorter/longer text run results) and how it draws (smaller, larger glyphs).

@xiaochengh
Copy link
Contributor

One subtle issue is that, what exactly is the value being overridden? It should not be the font-size property value, neither computed nor used, since they work at different levels and should better not have extra dependency.

While I agree with @jfkthame on the behavior details, I'd like to reiterate on this more fundamental question, and hope we can get a better answer.

So far, we've discussed various metrics/values that the proposed descriptor should or should not interact with. My concern is that this is not a clean way to write a definition, as in this way we need to specify the interactions with an exhaustive list of metrics/values, which we probably don't have. And it's error-prone.

That's why I proposed that the descriptor is a modification to the font selection algorithm in #6075 (comment). In this way it should satisfy all the detailed behaviors that @jfkthame proposed.

The definition I proposed still looks a bit hacky and is just borderline acceptable to me. I'll be happy to see a better alternative.

The proposal would be to add a descriptor taking a percentage and effectively functions the same as font-size-adjust for a given scale factor.

This doesn't look correct to me, as font-size-adjust is applied to the used font-size of the element instead of any font face. It also seems a bit risky since there are too many things depending on font-size...

@faceless2
Copy link

faceless2 commented Mar 9, 2021

We think of font-size-adjust as a scaling factor applied to the rendered glyph and its advance, nothing more. It has no effect on em or any other units, so if the intention is for this property is to match the same behaviour I'd agree with @drott

It also seems a bit risky since there are too many things depending on font-size

precisely why I think this should have no impact on any metrics. So I'm a bit worried about this:

But if ascent etc are not overridden by descriptors, the font's normal metrics will be affected by the scale factor.

If we're going to be adjusting ch, ic etc. then how is that going to be applied to an element that contains two fonts in the font-family, one with scaling and one without? How much letter spacing is applied in this example?

@font-face {
    font-family: "foo";
    scale-factor: 2;
    unicode-range: U+41;
}
<div style="font-size: 10px; font-family: foo, serif; letter-spacing: 1ch">AB</div>

I think a clear distinction needs to be made between ascent-override etc. which are set in the @font-face and apply only to that family; and units, which apply to an element that may comprise of multiple font families. If the scaling factor applies to the former type of property, I don't really have an opinion but it's not going to be problematic either way. But I'm nervous about scaling applying to units in any way, because I don't see how it can be applied.

@faceless2
Copy link

On reflection, I'll answer my own question: the letter spacing in that example is whatever the width of "0" is in the first available font, which - because "foo" doesn't declare U+20 - is "serif". So I don't think this is an issue and I'll withdraw my concerns. As you were!

@jfkthame
Copy link
Contributor

jfkthame commented Mar 9, 2021

That's right -- and the same applies to all the units etc that are based on font metrics (like ch and ex): they don't vary according to which font face actually ends up getting used, which could be different for each character within the element, they're defined in terms of the "first available font" or similar language.

So if the first available font [for the specific character on which the measurement is based] has a glyph scaling factor in effect, that contributes to the metric it reports. But whatever the metric is, it's consistent throughout the element regardless of the mix of actually-used faces.

@xiaochengh
Copy link
Contributor

xiaochengh commented Mar 9, 2021

We think of font-size-adjust as a scaling factor applied to the rendered glyph and its advance, nothing more.

I suppose we also need to scale the ascent, descent and line gap metrics, when used for line-height: normal?

And these seem enough for a good text layout, so I don't think we should have anything else affected.

@fantasai
Copy link
Collaborator Author

fantasai commented Mar 9, 2021

@drott This scaling needs to affect the baseline table, otherwise the glyphs won't actually line up. (The purpose of baseline tables is to get proper optical alignment across fonts. It can't do its job if you scale the table but not the glyphs or vice versa.)

@jfkthame The ascent/descent metrics are generally based on the size of the gyphs, right? They're there to show how much space to reserve for the glyphs. The main use case for adding overrides for them was because OpenType has multiple sets of ascent/descent metrics and platforms can't agree on which set of metrics to use, not because we needed arbitrary overrides; I expect most cases the override value will match one or the other built-in ascent value. As for effect on layout, the height of the line is based on line-height, which most people set explicitly anyway; if there's concerns about scaling affecting the line height, don't use line-height: normal. But I want this feature to work not just for cases where the font is not just a temporary fallback that will get erased in 5 seconds but also for cases where multiple fonts need to work together but their optical sizes don't match well without adjustment. Cases where this scaling factor is for a permanent, desired font. For those cases if the ascent-override is set to a value that corresponds to some typographic design reference for the glyphs, then that needs to scale with the glyphs.

@xiaochengh font-size-adjust is specifically defined to affect the "used font-size" (i.e. the one used to size and select the font) and not the "computed font-size" (i.e. the one used for inheritance and calculating em units etc.) for the same reasons as we're discussing here for the glyph size override. And we're careful about where we use "computed font size" rather than "used font size" for that reason (or should be, and should fix anywhere they're mixed up regardless). So I think these need to be kept in sync on how they behave, unless there's some particular reason why font-size-adjust and this feature need to be distinct in some particular detail in which case we can make that detail a well-considered exception.

@xiaochengh
Copy link
Contributor

So I think these need to be kept in sync on how they behave, unless there's some particular reason why font-size-adjust and this feature need to be distinct in some particular detail in which case we can make that detail a well-considered exception.

(The following assumes "these" mean font-size-adjust property and the proposed descriptor)

I don't think the new descriptor should affect the font-size property value, neither computed nor used, because it is ill-defined. Assume we have an element that uses multiple font faces, some of which have this scale factor and some don't. Then they would want to set different used font-size values to the same element.

A similar idea is that, only the first available font's glyph scale factor affects the used font-size of the element. While being well-defined on its own, this means we can't use it to harmonize an element with mixed fonts. I don't think this is the desired solution...

@fantasai
Copy link
Collaborator Author

@xiaochengh OK, I see what you mean. Yeah, neither font-size-adjust nor this descriptor affect the value of the font-size property. But they both affect the font-size value applied to the font. This is what we're currently calling the “used font-size” in the font-size-adjust spec. We might need to adjust the way it's described to avoid this point of confusion, but font-size-adjust and this descriptor nonetheless need to be defined the same way.

@xiaochengh
Copy link
Contributor

@fantasai Thanks for clarifying! Now that makes a lot of sense to me, and I think we are actually trying to define it in the same way.

And I guess some editorial work is needed, as I didn't see a shiny blue underlined term "used font-size" in the spec...

Effect on ascent-override/descent-override/etc.? [Scales with the scale factor.]

(Suppose "scales with the scale factor" means that if we want to achieve some specific values of ascent and descent, then we need to divide ascent-override/descent-override by the scale factor.)

Now I agree with this. This does not look completely straightforward to me, but is still reasonable if we define "used font-size" as the size applied to the font (instead of something per-element), and consider ascent-override etc as intrinsic properties of the font.

@fantasai
Copy link
Collaborator Author

Agenda+ to discuss accepting the proposal: an @font-face descriptor accepting a percentage that, like font-size-adjust, scales the computed font-size before using it to select the font face, thus affecting all metrics associated with the font (including those overridden via explicit @font-face descriptors) as well as the glyph outlines themselves, but not affecting em or line-height other than normal (since the computed font-size remains intact).

I suggest the name size-adjust, because it's an adjustment on the size; and the reference to font-size-adjust is appropriate, since it behaves the same way.

The use cases this addresses are:

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-fonts-5] Add glyph scaling override descriptor to @font-face, and agreed to the following:

  • RESOLVED: Add a size-adjust descriptor to @fontface, accepting a %. Applies a scale factor. Impacts all associated metrics of the font, including the outlinet b/c does not effect computed fonts size does not effect em
The full IRC log of that discussion <dael> Topic: [css-fonts-5] Add glyph scaling override descriptor to @font-face
<dael> github: https://github.com//issues/6075#issuecomment-799915767
<chrishtr> q+
<dael> fantasai: Prop add a descriptor to fontface which accepts %. Scales computed fonts size before select font face. Effects all metrics and glyph outlines, but not computed font size.
<chris> q+
<dael> fantasai: size-adjust is suggested name b/c same as font-size-adjust in working
<dael> florian: Do you mean used font size is scaled?
<dael> fantasai: Yes
<dael> fantasai: Take computed font size, scale, but don't change computed font size
<dael> fantasai: 2 use cases. One is what advance-override tried which is the pitch of the font on the page scaling.
<dael> fantasai: The other reason to add is the glyphs in a different font for same font size look different sizes. We have font-size-adjust to equalize x height, but only works for writing modes where x-height matters. having a manually managed scaling allows authors to do size normalization for other writing systems and other aspects of font design
<dael> fantasai: Doesn't have a11y or i18n problems advance-override had
<dael> TabAtkins: Making nearly identical to font-size-adjust. Can we fold it in?
<chris> no we can't
<dael> fantasai: This is adescriptor.
<dael> TabAtkins: Nevermind. Cool
<Rossen_> ack chrishtr
<dael> chrishtr: fantasai, there's an issue about multiplying asc and desc
<dael> chrishtr: When used with line-height:normal
<dael> fantasai: Yes, asc and desc would get multiplied. If you want stable line-height you shouldn't use normal since that pulls things out of the font.
<dael> chrishtr: You would expect authors to apply asc overrides to counter effect?
<dael> fantasai: size-adjust needs to scale all font metrics. Not jsut for font-fallback, but other purposes. In case where; if you don't want to scale the advance for some reason you would unscale using asc and desc override properties
<florian> q?
<dael> fantasai: Most places where people care about this level of precision they are likely to not be using normal b/c you would have different line-heights for fallbacks. If you care a lot about precision of typesetting you'll use line-height:number
<fantasai> s/just/just used/
<Rossen_> ack chris
<myles> q+
<dael> chris: I wanted to point out we should have ex in spec. i can create. show with unicode range. For Arabic bigger, Thai smaller...that's an interesting use case. Want different normalization depending on script and this allows it. Interesting additional use case.
<Rossen_> ack myles
<dael> myles: We're going to have to make sure we define what happens when @fontface has this and ascent-override. Not hard, jsut have to decide
<dael> fantasai: For that question, all metrics overrides you apply as if they are what came in font and size0adjust is right before you select your font. You want to do that b/c when setting asc override you're trying to match to a point on the glyph, not arbitrary, and that needs to scale w/ glyph. If you scale the glyph and not asc it will be weird
<dael> myles: A few minutes ago you desc there were problems with font-size override property
<dael> fantasai: You mean advance-override?
<dael> myles: font-size-adjust
<dael> fantasai: Yeah, scales based on x-factor which doesn't help with something like Thai
<dael> myles: I check mdn and only one browser supports font-size-adjust. Should we deprecate that?
<dael> chris: It's a bit different. This is a %. We could harmonize. Could do in new descriptor rather than property. Not sure it makes sense to harmonize.
<dael> chris: If suggesting deprecate font-size-adjust I think it's a separate issue, but reasonable maybe
<dael> myles: I can open a separate issue
<dael> Rossen_: I was about to ask if these are additional clarifications we can work separately and sounds like they are
<Rossen_> q?
<dael> Rossen_: Any additional comments?
<dael> Rossen_: If not, summary of prop?
<dael> fantasai: Prop: Add a size-adjust descroptor to @fontface, acceptings a %. Applies a scale factor. Impacts all associated metrics of the font, including the outline. b/c does nto effect computed fonts size does not effect em
<dael> Rossen_: Objections?
<dael> jfkthame: Can we bikeshed name?
<dael> Rossen_: On the issue?
<dael> jfkthame: Okay
<dael> myles: Note sure I agree it wouldn't effect line-height
<dael> fantasai: DOesn't effect computed fonts size. Line-height is caluclated against that. THat's intentional
<dael> myles: I'll open an issue
<dael> Rossen_: Thanks myles. If you are concerned for the current resolution and don't think it's separate we can discuss now
<florian> [I think it would affect line-height: normal, but not line-height otherwise]
<dael> myles: I don't think need to now.
<dael> myles: I'd appriciate removing that part from resolution
<dael> fantasai: integral to getting this to work. line-height is a number, not a number per font. this is a per font scale factor. You cna't have it scale line-height. You can have it scale asc and desc but line-height has to be single, not array
<dael> myles: Thinking about normal
<dael> fantasai: Does effect normal
<dael> myles: Okay. Doesn't effect line height with a number. Does effect normal
<dael> Rossen_: Obj?
<chrishtr> \o/
<dael> RESOLVED: Add a size-adjust descriptor to @fontface, accepting a %. Applies a scale factor. Impacts all associated metrics of the font, including the outlinet b/c does not effect computed fonts size does not effect em

litherum added a commit to litherum/csswg-drafts that referenced this issue Mar 17, 2021
pull bot pushed a commit to FreddyZeng/chromium that referenced this issue Mar 22, 2021
Following the CSSWG resolution [1] and a tentative spec draft [2], this
patch implements all the boilerplates and plumbings for size-adjust
behind a flag. No new behavior is introduced.

A subsequent patch will implement the behavior change.

[1] w3c/csswg-drafts#6075 (comment)
[2] https://drafts.csswg.org/css-fonts-5/#descdef-font-face-size-adjust

Bug: 1037633
Change-Id: Ia4fa31906667ec6a667aa7aad10e5272eb9430fb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2773708
Commit-Queue: Xiaocheng Hu <[email protected]>
Reviewed-by: Rune Lillesveen <[email protected]>
Reviewed-by: Chris Harrelson <[email protected]>
Cr-Commit-Position: refs/heads/master@{#865324}
blueboxd pushed a commit to blueboxd/chromium-legacy that referenced this issue Mar 24, 2021
font-size-adjust is currently behind a flag, and is at experimental
status but not shipped yet [1].

This patch changes its status to test to make place for size-adjust, a
higher prioritized feature [2]. This is due to concerns that the current
(flawed) implementation of font-size-adjust may not work well with size-
adjust [3].

[1] https://chromestatus.com/features/5720910061371392
[2] w3c/csswg-drafts#6075
[3] https://chromium-review.googlesource.com/c/chromium/src/+/2773716

Bug: 451346, 1137633
Change-Id: I94b80dfce459c00555ebb5da301549dbec1b027c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2782848
Commit-Queue: Xiaocheng Hu <[email protected]>
Commit-Queue: Chris Harrelson <[email protected]>
Auto-Submit: Xiaocheng Hu <[email protected]>
Reviewed-by: Chris Harrelson <[email protected]>
Cr-Commit-Position: refs/heads/master@{#865896}
@fantasai fantasai added Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. labels Mar 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-fonts-5
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants