-
Notifications
You must be signed in to change notification settings - Fork 313
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
Add element parameter to font engine string methods #553
Add element parameter to font engine string methods #553
Conversation
Hey, and thank you for the kind words! I'm very interested to hear more about how well it works for you to combine the library with HarfBuzz. That is something that has been requested before, see in particular #211. And something I'd be interested in better integration with. I think what you are trying to do here is very good, but I believe it is not the right solution. In fact, we've had several requests in passing elements to the interfaces. However, this creates a dependency between the interface and elements that I'm not comfortable with. The reasoning is very similar to the one in this comment: #540 (comment), with the main difference being the system interface instead. To me, it would make a lot more sense to modify the font engine interface to make it pass whatever is needed for a good HarfBuzz integration. |
Hi; thanks for your response! I can definitely understand that point of view. In hindsight, this PR does feel like an ad-hoc solution. I am currently using my own font renderer with a custom As for integrating text-shaping: HarfBuzz buffers need a few bits of information to help with context:
Most of these can simply be inferred from the language. If the language is set to One suggestion I came up with on-the-spot is to add a language parameter (instead of the Rml::Element* parameter) to the font interface's methods. The language could then be determined from a |
Thanks for elaborating, it's very interesting. I certainly think passing the language as a parameter is a much better solution. I wonder if there is any chance that one might later want to expand with access to the other parameters you mention? In particular, I can imagine there might be some use for e.g. right-to-left. If yes, then to avoid having to break this API repeatedly, then I suggest that we create a new struct for this kind of data. Even if we only support language to begin with. What would be the proper term for this data, As for implementation of the In any case, let me know if this sounds reasonable to you, or if you have some other ideas. This was a very brief/rough description, so please let me know of any questions, and I can also help out around the implementation of this. |
Passing a structure is a great idea. The performance impact of calling Making it a property will also help with providing other context without relying on the language. For example, text direction and text script. An idea I had would be the three following properties: text-language: <string>;
text-direction: auto | left-to-right | right-to-left;
text-script: auto | <string>; The There could also be a shorthand property that combines the three: text-localization: <text-language> <text-direction> <text-script>; All of these could be added to enum class TextDirection
{
Auto,
LeftToRight,
RightToLeft,
};
struct TextShapingContext
{
String language;
TextDirection text_direction;
TextScript text_script; // TextScript being a custom class similar to NumberAuto but for strings.
float letter_spacing;
}; Let me know what you think about this. |
Great, I think we're starting to carve out a direction here. Generally, I do think that we should follow HTML/CSS when we can, unless there are very good reasons not to. In particular, there is already the On MDN, I see it is quite strongly encouraged to use the HTML attributes rather than CSS:
Also, there is no CSS-equivalent of the My suggestions:
The struct would then become something like this. struct TextShapingContext
{
String language;
TextDirection text_direction;
float letter_spacing;
}; Some implementation thoughts. Maybe take language as a const-reference? Do some measurements to see what is fastest. Also, some basic calculations tells me that the language is maximum 12 characters (excluding zero-terminator), so we could use that to pack it tightly in the computed values. But maybe a Even better, if we actually had a Harbuzz font engine to show all this off with :) |
That all sounds really good! So, to summarise everything:
These properties are then sent to the font engine (in a structure) from the element whenever the text's width or geometries are to be computed. This structure will contain the language string, text direction enumeration, and letter spacing. From here, the font engine can determine what else is needed to shape the text properly. One other thing to mention is the My intuition thinks that taking the language string as a constant reference would be the fastest, but I'll perform some benchmarks to properly verify this. Passing the text-shaping data to the font engine shouldn't have a lot of overhead if the user doesn't wish to use it.
I'm thinking that I will create a new sample project (similar to the bitmap-font one) that uses a HarfBuzz-based text renderer with buttons to change the language. If that's everything, then I might have a go at implementing this soon (though in a new pull request, I'd say). |
Yup, this sounds all good to me! I am fine with not adding the
Very cool, a separate sample sounds like a good idea, looking forward to seeing that! And then we could think about taking it into the default font engine later on. |
Alright, thanks for your guidance! I'll close this PR and get to work on implementing them. Expect a new pull request sometime in the near future! |
Hello! First, let me thank you (and all of the other contributors) for such an amazing library!
This pull request adds an
element
parameter to theGetStringWidth
andGenerateString
methods of the font engine interface. I am creating such a pull request since it can add extra context to text rendering that would otherwise be unavailable or difficult to acquire.For example, I am using a custom font engine with RmlUi to render text. It uses the HarfBuzz text-shaping library to properly shape the glyphs when text is rendered.
In order to perform accurate text shaping, HarfBuzz requires three bits of information: language, script, and text direction. It is possible to set a global language in my custom font engine, but there is an issue with documents that have multiple languages — such as a language-selection menu has the native names of each language, which would have several scripts and therefore may require different shaping rules to render each string correctly.
Adding the element parameter to the aforementioned functions will give the additional context needed to render text correctly. For instance, you can add a
lang="en"
attribute (changing"en"
to whichever language the element is) to the elements whose text has a constant language/language different to the global one. You can then check thelang
attribute in the font engine's methods and configure the appropriate text-shaping flags therefrom.