Fix hang when trying to display characters missing from the embedded font

When SolveSpace tries to display an Unicode code point (e.g. U+EA00 )
that does not exist in the embedded vector font (unifont.hex.gz) it hangs
in an endless loop in
`const BitmapFont::Glyph &BitmapFont::GetGlyph(char32_t codepoint)`.

The reason is that the binary search through the text file unifont-8.0.01.hex
that does the "lazy loading" of glyphs does not end.

Here is a short excerpt from the file:

```
D7FE:00007FFE63866DF66DEE6DDE63DE7FFE7FFE61866FBE638E6FBE6F867FFE0000
D7FF:00007FFE63866DF66DEE6DDE63DE7FFE7FFE61866FBE638E6FBE6FBE7FFE0000
F900:0080108810881FF8100800007FFE00000FF008100FF00810042002447FFE0000
F901:00047FFE008010841FFE10841FFC10841FFC10840880050003000CC0703E0000
```

When searching for `0xEA00` after some iterations of the while loop
2450010bbf/src/resource.cpp (L567)
both `first` and `last` end up pointing to F900. After that on each
consecutive iteration of the loop `last` ends up pointing to the LF (0x0A)
just before F900
2450010bbf/src/resource.cpp (L585)
and then `mid` ends up back on F900 here
2450010bbf/src/resource.cpp (L570)
and this will repeat enlessly.

The solution is to do
```
                    first++;
```
here
2450010bbf/src/resource.cpp (L591),
which will make `first==last` and change whe while loop contition to `while(first < last) {` thiw will
allow the while loop to exit.

Tested with
- 0xEA00 - non existent, not found in 16 iterations.
- 0xF900 - exists but takes exactly 16 iterations of the binary search to finish
- 0x0000 - found in 16 iterations
- 0xFFFD - the replacement Unicode code point for non-existing glyphs. Also the end of the font.
- 0xFFFFF - a codepoint beyond the end, not found and does not cause an exception

The lazy parsing of the vector front was introduced here.
645c2d90ac

Fixes #1150
This commit is contained in:
ruevs 2021-12-16 18:51:27 +02:00 committed by phkahler
parent 2450010bbf
commit e07b082eb8

View File

@ -564,7 +564,7 @@ const BitmapFont::Glyph &BitmapFont::GetGlyph(char32_t codepoint) {
// Find the hex representation in the (sorted) Unifont file. // Find the hex representation in the (sorted) Unifont file.
auto first = unifontData.cbegin(), auto first = unifontData.cbegin(),
last = unifontData.cend(); last = unifontData.cend();
while(first <= last) { while(first < last) {
auto mid = first + (last - first) / 2; auto mid = first + (last - first) / 2;
while(mid != unifontData.cbegin()) { while(mid != unifontData.cbegin()) {
if(*mid == '\n') { if(*mid == '\n') {
@ -588,7 +588,10 @@ const BitmapFont::Glyph &BitmapFont::GetGlyph(char32_t codepoint) {
if(foundCodepoint < codepoint) { if(foundCodepoint < codepoint) {
first = mid + 1; first = mid + 1;
while(first != unifontData.cend()) { while(first != unifontData.cend()) {
if(*first == '\n') break; if(*first == '\n') {
first++;
break;
}
first++; first++;
} }
continue; // and last stays the same continue; // and last stays the same