From e07b082eb810d2088c92b97d04e864a4ab95816f Mon Sep 17 00:00:00 2001 From: ruevs Date: Thu, 16 Dec 2021 18:51:27 +0200 Subject: [PATCH] Fix hang when trying to display characters missing from the embedded font MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 https://github.com/solvespace/solvespace/blob/2450010bbfa20a1ffbf5fd90b85c4b941f56cb16/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 https://github.com/solvespace/solvespace/blob/2450010bbfa20a1ffbf5fd90b85c4b941f56cb16/src/resource.cpp#L585 and then `mid` ends up back on F900 here https://github.com/solvespace/solvespace/blob/2450010bbfa20a1ffbf5fd90b85c4b941f56cb16/src/resource.cpp#L570 and this will repeat enlessly. The solution is to do ``` first++; ``` here https://github.com/solvespace/solvespace/blob/2450010bbfa20a1ffbf5fd90b85c4b941f56cb16/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. https://github.com/solvespace/solvespace/commit/645c2d90ace3e48c639c49512fe1d7a43beb1755 Fixes #1150 --- src/resource.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/resource.cpp b/src/resource.cpp index 7b19081..258c73a 100644 --- a/src/resource.cpp +++ b/src/resource.cpp @@ -564,7 +564,7 @@ const BitmapFont::Glyph &BitmapFont::GetGlyph(char32_t codepoint) { // Find the hex representation in the (sorted) Unifont file. auto first = unifontData.cbegin(), last = unifontData.cend(); - while(first <= last) { + while(first < last) { auto mid = first + (last - first) / 2; while(mid != unifontData.cbegin()) { if(*mid == '\n') { @@ -588,7 +588,10 @@ const BitmapFont::Glyph &BitmapFont::GetGlyph(char32_t codepoint) { if(foundCodepoint < codepoint) { first = mid + 1; while(first != unifontData.cend()) { - if(*first == '\n') break; + if(*first == '\n') { + first++; + break; + } first++; } continue; // and last stays the same