-
Notifications
You must be signed in to change notification settings - Fork 11
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
Better support for vertical text #124
Conversation
Thanks! I tested Monglian and Japanese texts. Fonts are Noto Sans Monglian and M+ 1 Regular.
This is just a quick report. I'll try to make a minimal test case if needed. |
@hajimehoshi Thank you for the quick tests ! Could you make sure you use Also, in sideways mode, it seems you do not use |
I'll test those tomorrow. Could you tell me what APIs were newly added? |
So I've updated the PR description with links towards the new API : |
yOffset is float32 while YAdvance is fixed.Int26_6. How should I convert this appropriately? |
I utilized The Monglians seems fine! I found that mixing Japanese characters and English characters doesn't work well. In the above figure "あHello, World.あ"'s Y offsets does match. The last あ overlaps the adjacent English sentence. Should I adjust this with Thanks! EDIT: You can test this with go run github.com/hajimehoshi/ebiten/v2/examples/texti18n@874d48f945b0d0480d2975e2a7ad69120fd949b4 EDIT2: Arabic results was also changed unexpectedly. I'll take a look... EDIT3: Fixed the Arabic issue at 363a4f853717300361c6c17ac51dc4e513b87aef by reversing the split inputs for RTL texts. |
Since YAdvance has been scaled by Input.Size (output = font_units * Size / face.Upem), and Sideways expects a value in font units, you should pass YAdvance / (Size * face.Upem) to convert back to fonts units. More precisely, you could use func toFloat32(a fixed.Int26_6) float32 {
return float32(a) / 64
} |
OK, I actually did this: func fixed26_6ToFloat32(x fixed.Int26_6) float32 {
return float32(x>>6) + float32(x&((1<<6)-1))/float32(1<<6)
} EDIT: Your |
So, the simple conversion like |
I think I was misunderstanding. Your intention is like this? fixed26_6ToFloat32(-YAdvance) / Size / float32(face.Upem()) |
I'm sorry for spamming, but
YAdvance is a value in the scaled units, while Sideways expects a value in the font units. So
seems correct, but am I missing something? With multiplying Upem, the rendering result is broken, but I still don't understand why |
I agree with this formula. Hum... I'll try to render the glyphs from your example and investigate tomorrow. |
@hajimehoshi I've rendered the Mongolian and (a sample of) Japanese texts, and have noticed none of the visual issues you have found. See the outputs I get : Could you try and find where your pipeline differs from this one ? |
I'll check this later, but
Isn't the value almost 0? EDIT: NVM, I missed that |
So, I've explored a little bit the Opentype BASE table and thought about baseline. I think there are two different concepts :
Implementing the first one is probably desirable, but postponed to another PR. Implementing the second one is visually more important, and may be done quite simply, as in 582c627. Now, calling We may want to fine tune the implementation of @hajimehoshi Could you confirm that using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benoitkugler Thanks, as always, for the excellent work here. It's exciting to see us grow better vertical text support. The changes make sense, and seem to be implemented at the right level of abstraction. It's unclear to me whether this needs a second review from @andydotxyz. I don't think the public API is breaking, but it is changing (the new exported fields/methods on Direction).
@hajimehoshi Thank you so much for the excellent bug reports and features that drove this change. Thanks to your efforts, Ebitengine, Gio, Fyne, and (hopefully) many more projects will now have more correct text shaping.
Now everything looks fine. Thank you very much! What I did is to add these lines to expect the side effect of line := shaping.Line{out}
line.AdjustBaseline()
// After that, `out` is directly used and `line` is no longer used. |
Unfortunately this is an issue as the baseline are not alinged with English texts. In the above figure, I rendered |
Perhaps we should align the text not by the ascent/descent of the particular glyphs within it, but by the face's advertised ascent/descent? That should be independent of specific glyph contents, and it should look decent. |
This particular issue is more of a line-spacing/line-height problem. The typesetting repo doesn't currently implement this part of the text display process internally. It's up to applications to decide where to start the baseline of each line of text. See the discussion here for some examples of the complexities inherent in this space: gioui/gio#123 |
I agree with you. A face's metrics should be used rather than each glyph's metrics.
OK, but if an application moves the dot position for each line with a constant interval, each line should be aligned, right? |
Well, in theory, the shaper (harfbuzz) could decide to move glyphs up (for instance if the font provides a positioning table), so I'm not sure this promise holds. |
Yeah, but in my example, the same size and face were used. I'm OK even if lines are not aligned when multiple faces or sizes are used. |
I think conceptually it's correct to shift the gap between dots by a fixed value. It's true that situationally the glyphs may look misaligned if the shaper did something fancy, but that would be a feature, not a bug. |
To achieve this, would we shift the glyphs by half the distance from the face's baseline to its ascent? I'd expect that to visually center the above-the-baseline portion of the text. I don't know for sure if this would be correct for all scripts, but it certainly would be for Latin and CJK. |
Hum, I've just tried that and it seems to move the glyphs a bit too much down. I think the proper way to go would be to align the baseline : ideographic and roman. However, it seems to me this does not solve the "only english" example. Maybe, in this case we could shift by the font advance as @whereswaldon suggested earlier. |
Well, what do you think of handling the baseline issue in a separate PR ? This one is already large and it seems we need more discussion on how to do it anyway. |
Fine by me |
+1. I'm fine with this issue addressed in another PR. I really appreciate your team's hard work! |
@andydotxyz friendly ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this, and my apologies for the delay.
I had hoped to test this by using it in our render package but I am not managing to get the time for such coding sorry.
A couple of comments inline, the only one that is a change request being the typo in docs.
I do wonder though, and may welcome other comments, if adding the rasterising render code here might start duplicating the render
repo and whether it would be worth testing this through usage of the rasteriser we maintain as a public API?
di/direction.go
Outdated
} | ||
|
||
// SwitchAwis switch from horizontal to vertical (and vice versa), preserving |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SwitchAxis probably ;) The linter should have caught this, perhaps our CI needs a few improvements.
Possibly "switches" not "switch" as well if this line is being updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, thank you.
shaping/output.go
Outdated
// Note that this method only update cross-axis metrics, | ||
// so that the advance is preserved. As such, it is valid | ||
// to call this method after line wrapping, for instance. | ||
func (l Line) AdjustBaseline() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading the doc implies this should be called AlignBaselines
instead.
Just a thought, not a change request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added an "s" to imply each run may be shifted.
@@ -0,0 +1,195 @@ | |||
package shaping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to look at whether this is needed in the typesetting repo as there is more render work in the render
repository, it would be a shame to duplicate for test purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this file seems a bit out of place, but, in the meantime, I found this quick and dirty visualisation tool very handy when developing.
As you said, a better solution would be to use render
. Perhaps we can keep this file for now, and once render
supports vertical text, move the examples there and remove shaping/render_test.go
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
This PR aims at fixing #111, by supporting "sideways" glyph orientation for vertical text.
It is roughly divided in two parts :
Direction
, and implementing "sideways" mode inShape
. A convenience method is provided :GlyphOutline.Sideways
to be used by renderers to rotate glyph.Segmenter.Split
The only change required for users/renderers is thus to check against the
Ouput.Direction.IsSideways()
boolean, to properly rotate glyphs when rendering.Happy to read your thoughts !
(@hajimehoshi Maybe you would like to test this change ? The code in
ExampleShaper_Shape
anddrawVGlyphs
may be useful to do so)