red / REP

Red Enhancement Process
BSD 3-Clause "New" or "Revised" License
10 stars 4 forks source link

WISH: query font metrics #136

Open hiiamboris opened 1 year ago

hiiamboris commented 1 year ago

When displaying mixed content (images, text, widgets) I need to figure out how to best align the rows visually. Alas, there's no info available on Red level for that.

In particular, fonts have ascent/descent metrics which may be useful to know where font's baseline is located: https://stackoverflow.com/a/18111154

I'd like to have access to at least cross platform subset of these metrics.

luce80 commented 1 year ago

I strongly advocate for this. The more info about text metrics we have, the better it is.

hiiamboris commented 1 year ago

Another issue is with italics. I don't know if there even exists a good way to handle it, since it breaks the box model.

But anyway, here comes clipping even on simple enough fonts: r: rtd-layout [i font ["Times New Roman" 40] "pl" /font /i] view compose/deep [base white (size-text r) draw [text 0x0 (r)]] r: rtd-layout [i font ["Sylfaen" 40] "pl" /font /i] view compose/deep [base white (size-text r) draw [text 0x0 (r)]]

But it can be worse: r: rtd-layout [i font ["Edwardian Script ITC" 40] "pl" /font /i] view compose/deep [base white (size-text r) draw [text 0x0 (r)]]

luce80 commented 1 year ago

8 | . 😯. So size-text is returning the base-line width ? Did I already said "The more info about text metrics we have, the better it is." ?

hiiamboris commented 1 year ago

To convert font from SVG font size units (measured in pixels from baseline to baseline, thus equal to line height) into Red font size units (measured in points as em square height) we will need font's em height and line height, or em height and leading (line spacing).

A temp workaround is to measure line height for a known font size and assume the ratio between them is constant while font name is unchanged (only roughly holds).

qtxie commented 1 year ago

What's the API you propose? Options I can think of:

  1. Add a new query function, e.g font-metrics?.
    
    font-metrics? font-1

It returns an object! or a block! which contains the font information.



2. Add more fields (ascent, descent, line-cap, x-height, etc.) in font! object or a `metrics` field in it. It can be used as both input and output. After the font be created, those fields being filled if they were `none`. When used as input for making font, it's served as font spec.

3. other options you propose.
hiiamboris commented 1 year ago

Current font fields act as a selector (font name, size, style, weight, etc), but adding metrics into it would make it look like you can change them. You can't affect metrics, they're part of the font. Besides, you don't often need those metrics, so it would be wasteful to always have them in the font object.

So a function makes more sense to me. We have also:

>> ? rich-text
RICH-TEXT is an object! with the following words and values:
     rtd           object!       [stack color-stk out text s-idx s pos v l cur pos1...
     line-height?  function!     Given a text position, returns the corresponding l...
     line-count?   function!     number of lines (> 1 if line wrapped).

which probably should go somewhere into system context as well.

hiiamboris commented 1 year ago

What we sometimes want is to choose font em size based on known x-height or line-height. But from looking at DWrite I don't see any API there to do that. This is the key question then - can we do this?

If we can, I still don't think such metrics should be in the font, as changing them automatically should change font size, and then font size may again change the metric, leading to a recursive setting dependency. A better place would be https://github.com/red/REP/issues/139 which I imagine as some function that takes a set of constraints and returns sets of font parameters that satisfy.

luce80 commented 1 year ago

IMHO having a function that returns the necessary information is a good idea, having nothing is too few. DWrite seems a very high level interface, perhaps too high. What I think should be a good thing is something like [this](https://www.cairographics.org/tutorial/#:~:text=and%20cairo_fill().-,Understanding%20Text,-To%20use%20text).