Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.9
-
None
Description
In qtsvg/src/svg/qsvghandler.cpp, QSvgHandler::startElement() delegates <glyph …> elements (via some indirections) to createSvgGlyph() which doesn't understand what a glyph is. Most blatantly, it assumes only the first UTF-16 code-point matters, ignoring surrogate pairs and the grouping of Unicode characters into clusters to form a glyph.
- QSvgFont::addGlyph() accepts a single QChar as the "glyph", in qtsvg/src/svg/qsvgfont.cpp ❌
- createSvgGlyph() will pass u'\0' as that QChar for an empty string ❌
- QSvgFont::draw() examines each QChar of the str it is to draw to decide whether it has a glyph for each ❌
- If it fails to find a match, it uses the last empty-unicode glyph to represent the unknown QChar ❌
The spec of unicode says the attribute is:
One or more Unicode characters indicating the sequence of Unicode characters which corresponds to this glyph. If a character is provided, then this glyph corresponds to the given Unicode character. If multiple characters are provided, then this glyph corresponds to the given sequence of Unicode characters.
It then goes on to illustrate this with the case of ligatures, such as unicode="ffi", except that it uses character entities for the characters, for reasons lost on me – which reminds me to hope that, before createSvgGlyph() is called, or in the attribute.value() calls it makes, something is taking care to convert character entities (and, of course, encode the result in UTF-16).
So QSvgFont::addGlyph() should take a QString, not a QChar; as should QSvgGlyph()'s constructor, in qtsvg/src/svg/qsvgfont_p.h, and the member in which that stores it should also be a QString. At least one of these should assert the string is non-empty and createSvgGlyph() should return false for an empty unicode attribute (instead of forwarding the empty string to the above), because that is an error. Likewise, QSvgFont::m_glyphs should be a mapping (not from QChar but) from QString to QSvgGlyph.
Then QSvgFont::draw() should probably, instead of iterating the QChar that make up the string, have a QStringView tail{str} and ask whether there is any QString glyphText key of QSvgFont::m_glyphs for which tail.startsWith(glyphText) is true; if so, consume the longest such prefix, tail = tail.sliced(glyphText.size()), and draw the glyph. If not, and tail isn't yet empty, advance tail by one Unicode character (which may be a surrogate pair), tail = tail.sliced(surrogate ? 2 : 1). I do not know what it should do about that Unicode character, but those responsible for font-rendering might have some suggestions; it may be that the rendering should fall back to some other font for such characters. Either way, see whether what's left of tail starts with another glyph key, repeat until done.
I have not studied this code in great depth, only looked at some code matthias_rauter asked me about, so there may be more Unicode-handling issues in this module. Feel free to ask, if in doubt.