-
Notifications
You must be signed in to change notification settings - Fork 213
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
Split text layouting and text outlining into two separate steps #728
Conversation
The feature thing is probably not solved very nicely... I'm open for suggestions on how else to do it. |
crates/usvg/src/text/layout.rs
Outdated
/// A text span. | ||
Span(Span), | ||
/// A path. | ||
Path(Path), |
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.
What is Path
here? The Path
node? Why?
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.
Yes, it's a usvg path. Right now it's basically just a decoration span. I guess I should rename the enum variant.
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.
Oh, so those are for underlines and stuff? Hm... good question about we suppose to store them.
I guess we need just a list of rectangles. Maybe something like:
struct Layout {
fragments: Vec<TextFragment>,
underlines: Vec<NonZeroRect>,
overlines: Vec<TextFragment>,
strikethrougs: Vec<TextFragment>,
}
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'm not sure I understand, are you suggesting to store text fragments that have different decoration spans in different vectors? But that would mess up the order, no? What problem do you see with the current approach? By storing decorations as paths and text spans in the same vector, we can simply iterate over them in the order they are defined in the vector and render them separately so we don't need to worry about that.
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.
And it's also nice if I as a consumer of the API don't need to worry about resolving the text decorations myself but can simply render the resulting paths.
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.
Actually... What I could do is that we store the paths of underlines, line-throughs and overlines in the span itself. And then we basically only have a list of spans. This might be a bit cleaner. I'll go ahead and try to implement this.
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.
My problem is that text decoration should not be part of TextFragment
. Because it's kinda isn't.
If we have a underline over the whole text - then we have a single line/path. Why should it be part of TextFragment
? It doesn't make any sense to me.
In case of text-on-path decorations can be rotated, meaning just a Rect wouldn't be enough. So Path is fine for now.
And no, no one would be resolving text decoration manually, mainly because it would be impossible.
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.
As mentioned below, I've removed TextFragment
and store text decorations with the span now, I hope that's better!
Looks good to me. I'm still confused why we need The current limitation is that there is no way to get the original text/character position from the layout, which will be useful when generation a PDF with |
I removed text fragment now. What do you think?
I think it should be okay because I will still load the requested font and then save the cmap into the PDF, which should be enough (at least that's what Typst does and it seems to work fine). But I guess I will find out soon. |
You cannot really get a Unicode character from TrueType |
Oh damn, yeah, you are right, I need to somehow store the corresponding string for the glyphs... Will see if I can figure out how. |
Actually, sorry, there is one more small thing I would like to implement, so it would be good if we could hold off merging for now. I'll write here once I think it's done. |
Okay well, I've managed to produce the same visual output for all test cases but embedded text instead, so from my side I have everything I need in that regard. I still want to get copy-pasting to work, so still want to try to figure out a way to map the glyphs to their respective character, but I guess this can happen in a separate PR in the next few days, if I find the time. I'm already pretty happy with what I have for now. :D |
Sure, sounds good. I'm still trying to understand how do you handle decorations. I'm not sure they should be part of |
So, I just checked with the following SVG: <svg id="svg1" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"
font-family="Noto Sans" font-size="64">
<title>Simple case</title>
<path id="crosshair" d="M 20 100 L 180 100 M 100 20 L 100 180"
stroke="gray" stroke-width="0.5"/>
<text id="text1" x="32" y="100" text-decoration="underline">Te<tspan fill="green">x</tspan>t</text>
<!-- image frame -->
<rect id="frame" x="1" y="1" width="198" height="198" fill="none" stroke="black"/>
</svg> In this case, there will be 3 spans and each of them has a separate underline (but each underline only covers the range of the glyphs they contain, so they are not overlapping)... But I think it should be fine like that, right? I mean it can't be noticed that they are three different underlines, anyway. Or is that a problem? |
Great, the current implementation also breaks underlines. I don't know how my own code works anymore... I wrote it like 4 years ago. Either way, let's leave decoration as a part of a span. Not ideal, but not breaking either. |
Thanks! |
I had to update one reference image, but it was only a one pixel difference. Probably due to some float rounding issue.