Skip to content

Conversation

valadaptive
Copy link
Contributor

Resolves #320.

Not sure if it's too annoying to always have to specify whether you want the line height to be relative or absolute, but I think this is nicer than the roundtrip of absolute -> relative -> absolute that happens currently if you need to specify absolute line height.

@valadaptive valadaptive requested a review from DJMcNab March 30, 2025 10:44
Copy link
Contributor

@nicoburns nicoburns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to me. I'm not too worried about API ergonomics, as I suspect it will be largely other libraries/frameworks consuming Parley so I doubt this will need to be typed manually that much.

@waywardmonkeys
Copy link
Contributor

I would like another review or two on this one… timebix it to within 48 hours.

Copy link
Member

@xorgy xorgy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a reasonable way to do this, but I would like an impl From like we have for font families.

Copy link
Contributor

@waywardmonkeys waywardmonkeys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am concerned about the ergonomics. I'm also not sure about having something where almost everything in Parley is absolute, but this one was relative, but now we want to make it do both.

I also don't like a From impl that returns a relative one since looking at the code, it won't be at all obvious which one it is, without reading docs or looking at the implementation.

This might be different if we had a Percentage or similar wrapper class or something.

Another option might be to make this always be absolute and require that the user of the API do the multiplication / scaling themselves.

I'd like to hear what @dfrg thinks about all of this.

(Marking as request changes to be sure we address this before something is merged. I'm not against some sort of change, just want us to get it right with consensus.)

@xorgy
Copy link
Member

xorgy commented Mar 31, 2025

For clarity, From<f32> was not what I had in mind, but rather From<LineHeight> for StyleProperty (like From<GenericFamily> for StyleProperty, where there is no ambiguity).
The builders accept impl Into<StyleProperty>, which is why we are able to push a GenericFamily directly.

@valadaptive valadaptive force-pushed the absolute-line-height branch from c3ca360 to 3ba13e1 Compare March 31, 2025 05:47
@valadaptive
Copy link
Contributor Author

For clarity, From<f32> was not what I had in mind, but rather From<LineHeight> for StyleProperty (like From<GenericFamily> for StyleProperty, where there is no ambiguity). The builders accept impl Into<StyleProperty>, which is why we are able to push a GenericFamily directly.

That would make much more sense 🤦

I am concerned about the ergonomics. I'm also not sure about having something where almost everything in Parley is absolute, but this one was relative, but now we want to make it do both.

My main concern is that going from relative to absolute units while keeping the same type for both would result in existing code silently doing the wrong thing, and API consumers would have to track down all the places they're passing in either a StyleProperty::LineHeight or a TextStyle.

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like where this PR takes us. I think it is a better state than before this PR, but I think that to move it where I'd want us to be would require a second breaking change.
Edit: To clarify, if we were to make this change, we'd definitely do it gracefully; that is, we would for example deprecate the existing LineHeight.

But I'm also not really sure where I want us to be. My gut reaction is that we should only support absolute line heights, and that relative line heights are out-of-scope.
The problem with not having a reasonable default line height is that people will evaluate Parley, get an extremely broken rendering, and not know how to debug it.

To clarify, this PR isn't blocking forward progress in egui, right?
If that's the case, my gut reaction is to ask you to continue to use the (awful) workaround of pre-dividing by the font size for now.

I think this probably needs Chad's input.

@@ -22,6 +22,14 @@ pub enum WhiteSpaceCollapse {
Preserve,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineHeight {
/// Line height specified as a multiple of the font size.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is a relative line height ever affected by the selected font (not just now, but is that something we might theoretically ever want?). That to me would be the only reasonable argument for keeping a relative line height around long-term. See for example line-height: normal, for a case where this does change based on the font family.
The other arguments which I think can be dismissed:

  • CSS overloads the line-height property to mean both
  • It's a pretty bad breaking change

There is another argument, which is one of defaults: any default absolute line height is stupid.

Copy link
Contributor

@nicoburns nicoburns Mar 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is a relative line height ever affected by the selected font (not just now, but is that something we might theoretically ever want?). That to me would be the only reasonable argument for keeping a relative line height around long-term.

It's not now in Parley, but it used to be (and I suspect this is why Parley currently uses relative line height). It was changed in #84 to match CSS (which defines line height relative to the nominal font size). Previously it took into account the metrics from the font.

Whether this is ever desirable I'm not sure.

@dfrg
Copy link
Collaborator

dfrg commented Mar 31, 2025

If we’re going to make this configurable then it would be nice to offer an option to fully respect font metrics as the code originally did.

That is, I’d like to see something like:

enum LineHeight {
    MetricsRelative(f32),
    SizeRelative(f32),
    Absolute(f32),
}

where the first is the original behavior, the second is the current behavior and the last does what this PR proposes. For the first two variants, the associated value is a multiplier. The default should be MetricsRelative(1.0) because this is generally what you want unless you’re dealing with CSS.

In a better world, the line breaker would take a callback to determine line height so we don’t have to be opinionated but we’re not there yet.

@valadaptive
Copy link
Contributor Author

The other arguments which I think can be dismissed:

  • CSS overloads the line-height property to mean both

  • It's a pretty bad breaking change

There is another argument, which is one of defaults: any default absolute line height is stupid.

Is that third argument one that you're putting forward or dismissing?

If we’re going to make this configurable then it would be nice to offer an option to fully respect font metrics as the code originally did.

Agreed. If others are fine with your proposed API, I could try implementing that. I think egui's old font layout code may also be metrics-relative?

In a better world, the line breaker would take a callback to determine line height so we don’t have to be opinionated but we’re not there yet.

This ties into some discussion in #325 (from @nicoburns):

My main observation beyond what you've written is that the BreakLines struct is already well setup for incremental layout where Parley lays content out up to a point, yields control flow back to the caller, and then the caller run it's own logic and calls back into Parley when it's ready.

This would definitely be very helpful. Right now, the line breaking code doesn't seem to even calculate line height until the finish method after all the lines have been broken (right now, unless I'm doing something wrong, the vertical advance returned by BreakLines::break_next is always 0.0 as a consequence). I'm not sure if this is intrinsic to the architecture or just how it happens to be implemented now, but it'd be nice to change.

Some CSS vertical alignment properties require two-pass layout vertically (they're relative to the bounds of the line, but the bounds of the line depend on vertical alignment, so items with those alignments are aligned in a second pass). Not sure how that would interact with the line breaking code if we want to support custom callbacks.

@DJMcNab
Copy link
Member

DJMcNab commented Mar 31, 2025

There is another argument, which is one of defaults: any default absolute line height is stupid.

Is that third argument one that you're putting forward or dismissing?

I'm putting it forward; that is to say, I don't dismiss it out of hand. I don't class it as a "definite" blocker for an "absolute line height only" world, but it's an argument against it.

I think with Chad's proposal, we can actually remove SizeRelative entirely. If we want a mode based on the font's metrics (which is pretty reasonable), then I agree that a default based on metrics is what we want. Although any such method does still have the issue of jumpy (/potentially overlapping(?)) rounded line heights.

I agree that if BreakLines would let you handle this, say by post-hoc specifying the "real height" of a line once it is broken, that would make the most sense. That way, you can implement whatever rounding you like even when you're metrics aware. But that needn't happen in this PR; it's orthogonal.

So concretely, my suggested way forward is to change this to:

enum LineHeight {
    MetricsRelative(f32),
    Absolute(f32),
}

and wire that up. Wiring up RelativeSize if we decide we want it can be a very quick follow-up, as a rewrite layer into Absolute (which is why I say we don't need it; the user can do so themselves if they want it).

@nicoburns
Copy link
Contributor

My take on SizeRelative is that I think it's nice from an API perspective (esp. if we're going to have an enum anyway) as it effectively documents how to achieve that effect. And it's a minimal cost to us from a maintenance perspective (a single multiply). But I don't feel super-strongly about this as it is indeed easy to build this on top of absolute line height.

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding MetricsRelative needn't block this PR, and it seems pretty settled that we want LineRelative

@xStrom
Copy link
Member

xStrom commented Apr 29, 2025

I agree with Nico that having SizeRelative is an easy ergonomics win if we're already going enum. The implementation burden is trivial and it doesn't really make API consumers' life harder, because resulting line heights are always just absolute f32, so no matching required.

Thus, I support Chad's API proposal of having all three variants.

@valadaptive
Copy link
Contributor Author

I'll let someone else redo this PR with whatever consensus exists. This seems like a quagmire and the current hack/workaround is good enough for my egui work.

github-merge-queue bot pushed a commit that referenced this pull request May 24, 2025
This implements @dfrg's
[proposal](#326 (comment)),
since most people agreed it was the way forward.

If you don't want `FontSizeRelative`, I can remove
it--`MetricsRelative(1.0)` is a sensible default that works at all font
sizes. But some people leaned towards keeping `FontSizeRelative`.

The default line height has been changed from `FontSizeRelative(1.2)`
(what I believe CSS uses) to `MetricsRelative(1.0)`. This means a lot of
the snapshot tests will change as well.

---------

Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
Co-authored-by: Kaur Kuut <strom@nevermore.ee>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow specifying line-height in absolute units more conveniently
7 participants