TextMetrics & rendered text changed from v1.0.2 to v^2.0.0
Closed this issue · 4 comments
About
Texts aren't rendered same as in v1.0.2, TextMetrics
are different for all textBaseLine
but it is most noticeable for top
&& bottom
, when middle
|| alphabetic
are used changes are very small.
baseline: alphabetic | ![]() |
![]() |
---|---|---|
baseline: bottom | ![]() |
![]() |
old: v1.0.2, new: v2.0.1
Notice: how text is shifted upwards when baseline: bottom
Reproducible example
Toggle me!
function drawTestText() {
const width = 150
const height = 100
const canvas = new Canvas(width, height)
const context = canvas.getContext('2d')
context.fillStyle = 'white'
context.fillRect(0, 0, width, height)
context.strokeStyle = 'blue'
context.beginPath()
for (let i = 0; i < height; i += 10) {
context.moveTo(0, i)
context.lineTo(width, i)
}
context.stroke()
context.closePath()
context.font = '50px Lato'
context.fillStyle = 'black'
context.textAlign = 'left'
context.textBaseline = 'bottom'
const text = 'TEST'
const measurements = context.measureText(text)
console.log(measurements)
context.fillText(text, 25, 75)
context.beginPath()
context.strokeStyle = 'red'
context.strokeRect(
25 + measurements.lines[0].x,
75 + measurements.lines[0].y,
measurements.lines[0].width,
measurements.lines[0].height
)
}
Expected behavior
I am unsure about this, to be honest. This is causing me problems because I had fine-tuned my render functions to display text in specific positions based on TextMetrics. Primarily, I would like to know if this is/was an expected change between versions and, if possible, what caused it.
Nothing changed between v1 and v2 within skia-canvas itself, but it upgrades to a much newer revision of rust-skia, so things have almost certainly changed under the hood. However: one alternative explanation that comes to mind is that your system is now using gpu-based rendering as of v2 (in which case setting canvas.gpu = false
would yield different results).
That said, after looking over the way different baselines are computed (for #209) I think I've found some modifications that would better match the way browsers calculate offsets and determine the default leading when a lineHeight
value isn't included in the ctx.font
assignment.
More to come…
Nothing changed between v1 and v2 within skia-canvas itself, but it upgrades to a much newer revision of rust-skia, so things have almost certainly changed under the hood. However: one alternative explanation that comes to mind is that your system is now using gpu-based rendering as of v2 (in which case setting
canvas.gpu = false
would yield different results).That said, after looking over the way different baselines are computed (for #209) I think I've found some modifications that would better match the way browsers calculate offsets and determine the default leading when a
lineHeight
value isn't included in thectx.font
assignment.More to come…
It can't be a GPU thing as this happen also in CI and on my server, where there is none and also i have it specifically set to canvas.gpu = false
First of all, you're definitely correct that there's a vertical shift between version 1.0 and 2.0. What's odd though is that it's not in a fixed direction. Take a look at this animation alternating between versions and note how in some cases the text shifts up and in others down:
My hunch is that this is the result of Skia trying to align the text with the pixel grid rather than using whatever fractional y-position the metrics alone would position the text at. Another project using SkParagraph for typesetting has mentioned that it rounds the lineHeight to the nearest pixel (which could account for the unpredictable vertical shifts seen above).
The other place where it might be shifting the position is in its application of font hinting—something that it's currently not possible to disable but seems like it's also to blame for the unexpectedly dark font rendering mentioned in #202.
Changing baseline calculations to match browser behavior
Separate from this pixel grid-related shifting, there's also the issue of baselines being calculated differently in Skia Canvas than in browsers. The changes in d7a13d8 should result in a much closer match (as seen in the final gif below), but will necessarily mean that positioning will shift even further relative to the 1.0 behavior. Sorry for the lack of stability, but shooting for 'correctness' seems worthwhile in this case.
Version 1.0 vs browser
Version 2.1 (prerelease) vs browser
Version 2.0.2 disables font hinting by default, resulting in lighter text that's closer to what browsers produce. It can be re-enabled by setting ctx.fontHinting
to true
to get smoother but bolder text rendering.
Text baselines now consult the font metrics to calculate the line height (rather than defaulting to 1.2em) when ctx.font
only includes a size and not a /
-separated line height. This also results in layouts much closer to browsers'. The top
and middle
baseline positions now use a formula taken from the chromium source, so expect them to shift relative to 2.0.1.