Skip to content

Ability to obtain baseline Y offset #123

@JayTee42

Description

@JayTee42

I try to utilize cosmic-text to draw text to a bitmap and to obtain a tight bounding box around the result. Right now, I am confused by the calculation of the vertical offset of the text. To elaborate further, let us assume that we draw a single glyph, i.e. the letter "g", using a Buffer. For the sake of simplicity, we set line_height == font_size == 72.0 (i.e. we do not apply leading aka additional distance between the lines). When we call Buffer::draw(), the code first creates a LayoutRunIter whose line_y property is initialized as follows:

line_y: buffer.metrics.y_offset(),

In our case, y_offset() evaluates to 0.0 (no leading, see above) and therefore, our run starts at a vertical offset of 0.0. Now, we call next() on the iterator to draw the first run and observe that line_y is incremented by the line height which is equal to the font size (aka 72.0):

self.line_y += self.buffer.metrics.line_height;

Finally, we obtain the glyph image from `swash' and draw it to the given offset:

cosmic-text/src/buffer.rs

Lines 718 to 720 in bfb5eef

cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| {
f(x_int + x, run.line_y as i32 + y_int + y, 1, 1, color);
});

run.line_y still evaluates to 72.0 in our example. However, if I understand correctly, the swash image is positioned relatively to the baseline of the glyph. I did not find explicit confirmation for this assumption in the swash documentation, but the swash_demo repo provides an extensive sample for this. When drawing its layout, it incorporates the baseline into the vertical offset as seen here:

https://github.com/dfrg/swash_demo/blob/55aedbc8604201f1b4925e2b986db59b838dc062/src/main.rs#L493

In opposition, cosmic-text effectively places the baseline at the bottom of the line. When I try to draw my "g" glyph to the top-left corner of a bitmap and set my bounding box height to 72 pix, I end up with the following result:

g

How to fix this? I am not adept in typography, but for my understanding, the vertical offset must be corrected by the descent of the font as displayed here:

glyph

Indeed, to draw my glyphs to the bitmap, I tried to calculate the baseline of the font by myself to apply this correction. This approach works, but cosmic-text makes it pretty hard to implement it. Basically, I have to layout my line, obtain the FontID from the glyphs, query the Font from the FontSystem and do something like this:

let metrics = font.as_swash().metrics(&[]);
let total_height = metrics.ascent + metrics.descent;
let baseline = font_size * metrics.ascent / total_height;

In fact, this is about the same calculation that is done in the swash demo, see here:

https://github.com/dfrg/swash_demo/blob/d08ced5f1e92b62cd637415c1f66c440d737b31b/src/layout/line_breaker.rs#L324-L326

By using baseline instead of font_size (resp. the total line height) as vertical offset, I finally get the correct result. I can live with this approach, but it would be nice if cosmic-text made it easier for me to access the baseline offsets of the layout lines.

Sorry for the long explanation. I hope the issue has been made clear - and thanks for your awesome work on this crate!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions