Author Topic: Fonts are broken  (Read 4084 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Fonts are broken
« on: September 12, 2019, 11:41:26 am »
I don't know when the issue popped up in QB64, but our fonts are currently not working as intended for us.  Try this little code as a demonstration:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2. f = _LOADFONT("cour.ttf", 14, "MONOSPACE")
  3. FOR i = 0 TO 255

Ever since version 1.000, if we were to use "MONOSPACE", we could force the font to become a monospaced font if it wasn't.  (From the wiki: _FONTWIDTH can only measure monospaced fonts. "MONOSPACE" can be used to load a variable width font as a monospace font. )

As you can see from the small code sample above, that's not holding true at all now.  Our _FONTWIDTH is registering as 0, and when we manually print the width of our characters, we see that they vary in size by a few pixels. 

That monospace tag is no longer forcing fonts to become monospaced.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Fonts are broken
« Reply #1 on: September 12, 2019, 11:52:39 am »
Digging into this, it appears as if the fonts are only broken when QB64 searches for the font.  If you specify it manually, it doesn't appear to be an issue:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2. f = _LOADFONT("C:\Windows\Fonts\courbd.ttf", 20, "MONOSPACE")
  3. FOR i = 0 TO 255
  4.  
  5.  
  6.  
  7. f = _LOADFONT("courbd.ttf", 20, "MONOSPACE")
  8. FOR i = 0 TO 255
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Fonts are broken
« Reply #2 on: September 12, 2019, 12:11:54 pm »
Fix requires a quick patch to _LOADFONT, which we can find in libqb.cpp:

Code: C++: [Select]
  1.         int32 func__loadfont(qbs *f,int32 size,qbs *requirements,int32 passed){
  2.             //f=_LOADFONT(ttf_filename$,height[,"bold,italic,underline,monospace,dontblend,unicode"])
  3.            
  4.             if (new_error) return NULL;
  5.            
  6.             qbs *s1=NULL; s1=qbs_new(0,0);
  7.             qbs *req=NULL; req=qbs_new(0,0);
  8.             qbs *s3=NULL; s3=qbs_new(0,0);
  9.             uint8 r[32];
  10.             int32 i,i2,i3;
  11.             static int32 recall;
  12.            
  13.             //validate size
  14.             if (size<1){error(5); return NULL;}
  15.             if (size>2048) return -1;
  16.  
  17.  
  18.             //load the file
  19.             if (!f->len) return -1;//return invalid handle if null length string
  20.             int32 fh,result;
  21.             int64 bytes;
  22.             fh=gfs_open(f,1,0,0);
  23.            
  24.             #ifdef QB64_WINDOWS //rather than just immediately tossing an error, let's try looking in the default OS folder for the font first in case the user left off the filepath.
  25.                 if (fh<0&&recall==0) {
  26.                     recall=-1; //to set a flag so we don't get trapped endlessly recalling the routine when the font actually doesn't exist
  27.                     i=func__loadfont(qbs_add(qbs_new_txt("C:/Windows/Fonts/"),f), size, requirements,passed); //Look in the default windows font location
  28.                     return i;
  29.                 }
  30.             #endif
  31.             recall=0;
  32.             if (fh<0) return -1; //If we still can't load the font, then we just can't load the font...  Send an error code back.
  33.  
  34.             //check requirements
  35.             memset(r,0,32);
  36.             if (passed){
  37.                 if (requirements->len){
  38.                     i=1;
  39.                     qbs_set(req,qbs_ucase(requirements));//convert tmp str to perm str
  40.                     nextrequirement:
  41.                     i2=func_instr(i,req,qbs_new_txt(","),1);
  42.                     if (i2){
  43.                         qbs_set(s1,func_mid(req,i,i2-i,1));
  44.                         }else{
  45.                         qbs_set(s1,func_mid(req,i,req->len-i+1,1));
  46.                     }
  47.                     qbs_set(s1,qbs_rtrim(qbs_ltrim(s1)));
  48.                     if (qbs_equal(s1,qbs_new_txt("BOLD"))){r[0]++; goto valid;}
  49.                     if (qbs_equal(s1,qbs_new_txt("ITALIC"))){r[1]++; goto valid;}
  50.                     if (qbs_equal(s1,qbs_new_txt("UNDERLINE"))){r[2]++; goto valid;}
  51.                     if (qbs_equal(s1,qbs_new_txt("DONTBLEND"))){r[3]++; goto valid;}
  52.                     if (qbs_equal(s1,qbs_new_txt("MONOSPACE"))){r[4]++; goto valid;}
  53.                     if (qbs_equal(s1,qbs_new_txt("UNICODE"))){r[5]++; goto valid;}
  54.                     error(5); return NULL;//invalid requirements
  55.                     valid:
  56.                     if (i2){i=i2+1; goto nextrequirement;}
  57.                     for (i=0;i<32;i++) if (r[i]>1){error(5); return NULL;}//cannot define requirements twice
  58.                 }//->len
  59.             }//passed
  60.             int32 options;
  61.             options=r[0]+(r[1]<<1)+(r[2]<<2)+(r[3]<<3)+(r[4]<<4)+(r[5]<<5);
  62.             //1 bold TTF_STYLE_BOLD
  63.             //2 italic TTF_STYLE_ITALIC
  64.             //4 underline TTF_STYLE_UNDERLINE
  65.             //8 dontblend (blending is the default in 32-bit alpha-enabled modes)
  66.             //16 monospace
  67.             //32 unicode
  68.  
  69.             bytes=gfs_lof(fh);
  70.             static uint8* content;
  71.             content=(uint8*)malloc(bytes); if (!content){gfs_close(fh); return -1;}
  72.             result=gfs_read(fh,-1,content,bytes);
  73.             gfs_close(fh);
  74.             if (result<0){free(content); return -1;}
  75.            
  76.             //open the font
  77.             //get free font handle
  78.             for (i=32;i<=lastfont;i++){
  79.                 if (!font[i]) goto got_font_index;
  80.             }
  81.             //increase handle range
  82.             lastfont++;
  83.             font=(int32*)realloc(font,4*(lastfont+1)); font[lastfont]=NULL;
  84.             fontheight=(int32*)realloc(fontheight,4*(lastfont+1));
  85.             fontwidth=(int32*)realloc(fontwidth,4*(lastfont+1));
  86.             fontflags=(int32*)realloc(fontflags,4*(lastfont+1));
  87.             i=lastfont;
  88.             got_font_index:
  89.             static int32 h;
  90.             h=FontLoad(content,bytes,size,-1,options);
  91.             free(content);
  92.             if (!h) return -1;
  93.            
  94.             font[i]=h;
  95.             fontheight[i]=size;
  96.             fontwidth[i]=FontWidth(h);
  97.             fontflags[i]=options;
  98.             return i;
  99.         }

Swap that code in place of your existing _loadfont in libqb.cpp, purge libqb.cpp (via the batch file in the same folder), and you're all fixed.

Luckily this wasn't anything major which required a lot of work to fix.  The issue was shamefully simple -- placement of segments inside the routine which affect the values of our passed variables when we call the sub a second time with the Windows default path prepended to it...

Just add the "C:\Windows\Fonts\" to the fontname (if necessary), BEFORE we deconstruct the requirements, and we're golden.  ;)
« Last Edit: September 12, 2019, 01:43:57 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Fonts are broken
« Reply #3 on: September 12, 2019, 12:23:21 pm »
Hi. I just tried it, too. When you do it so beautifully, can you also just try to fix the cut font?
See this thread:
https://www.qb64.org/forum/index.php?topic=247.msg1301;topicseen#msg1301

But definitely good work this fix! Thank you for that.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Fonts are broken
« Reply #4 on: September 12, 2019, 12:39:34 pm »
Steve, how you test the C code? I replace it, but have again the same outputs? I use your second code and second FONTWIDTH return 0? New libqp.cpp size is 1 326 522 bytes, i already rewrited it in internal/c/libqp.cpp


Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Fonts are broken
« Reply #5 on: September 12, 2019, 12:44:33 pm »
Must IDE be new compiled?

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Fonts are broken
« Reply #6 on: September 12, 2019, 12:45:52 pm »
Steve, how you test the C code? I replace it, but have again the same outputs? I use your second code and second FONTWIDTH return 0? New libqp.cpp size is 1 326 522 bytes, i already rewrited it in internal/c/libqp.cpp

You need to run the purge_libqb_only.bat file inside the internal/c folder after making the changes, to get rid of the old *.o file and build a new one.

After that, just hit space or some other key in the IDE, with your test program, to make it recompile, and you should be able to take advantage of the changes from that point onwards.  (And why we have to hit a key to recompile is beyond me, but we do -- just like if we edit an $INCLUDE file or such, without making a change in the IDE itself.)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Fonts are broken
« Reply #7 on: September 12, 2019, 01:05:07 pm »
Aha! I did it as you write and I achieved ....
So I tried again and with the same result ...
I attach the CPP file as I edited it. I guess I did something wrong.



Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Fonts are broken
« Reply #8 on: September 12, 2019, 01:49:23 pm »
Aha! I did it as you write and I achieved ....
So I tried again and with the same result ...
I attach the CPP file as I edited it. I guess I did something wrong.

You did it right; the forums (and me) did it wrong.  In the previous post, where you copied the changes necessary for your version of libqb, I put the code in a codebox -- for QB64 code.   It needed to be in a codebox for C-code instead, as formatting matters a lot in C...

When the forums formatted the code to make it look like QB64 BASIC, it altered things beyond repair.

This line:            IF (size<1){ERROR(5); RETURN NULL;}

Is NOT this line:             if (size<1){error(5); return NULL;}

Code box has been fixed above, and here it is corrected as well (without ANY formatting):

Code: [Select]
        int32 func__loadfont(qbs *f,int32 size,qbs *requirements,int32 passed){
            //f=_LOADFONT(ttf_filename$,height[,"bold,italic,underline,monospace,dontblend,unicode"])
           
            if (new_error) return NULL;
           
            qbs *s1=NULL; s1=qbs_new(0,0);
            qbs *req=NULL; req=qbs_new(0,0);
            qbs *s3=NULL; s3=qbs_new(0,0);
            uint8 r[32];
            int32 i,i2,i3;
            static int32 recall;
           
            //validate size
            if (size<1){error(5); return NULL;}
            if (size>2048) return -1;


            //load the file
            if (!f->len) return -1;//return invalid handle if null length string
            int32 fh,result;
            int64 bytes;
            fh=gfs_open(f,1,0,0);
           
            #ifdef QB64_WINDOWS //rather than just immediately tossing an error, let's try looking in the default OS folder for the font first in case the user left off the filepath.
                if (fh<0&&recall==0) {
                    recall=-1; //to set a flag so we don't get trapped endlessly recalling the routine when the font actually doesn't exist
                    i=func__loadfont(qbs_add(qbs_new_txt("C:/Windows/Fonts/"),f), size, requirements,passed); //Look in the default windows font location
                    return i;
                }
            #endif
            recall=0;
            if (fh<0) return -1; //If we still can't load the font, then we just can't load the font...  Send an error code back.

            //check requirements
            memset(r,0,32);
            if (passed){
                if (requirements->len){
                    i=1;
                    qbs_set(req,qbs_ucase(requirements));//convert tmp str to perm str
                    nextrequirement:
                    i2=func_instr(i,req,qbs_new_txt(","),1);
                    if (i2){
                        qbs_set(s1,func_mid(req,i,i2-i,1));
                        }else{
                        qbs_set(s1,func_mid(req,i,req->len-i+1,1));
                    }
                    qbs_set(s1,qbs_rtrim(qbs_ltrim(s1)));
                    if (qbs_equal(s1,qbs_new_txt("BOLD"))){r[0]++; goto valid;}
                    if (qbs_equal(s1,qbs_new_txt("ITALIC"))){r[1]++; goto valid;}
                    if (qbs_equal(s1,qbs_new_txt("UNDERLINE"))){r[2]++; goto valid;}
                    if (qbs_equal(s1,qbs_new_txt("DONTBLEND"))){r[3]++; goto valid;}
                    if (qbs_equal(s1,qbs_new_txt("MONOSPACE"))){r[4]++; goto valid;}
                    if (qbs_equal(s1,qbs_new_txt("UNICODE"))){r[5]++; goto valid;}
                    error(5); return NULL;//invalid requirements
                    valid:
                    if (i2){i=i2+1; goto nextrequirement;}
                    for (i=0;i<32;i++) if (r[i]>1){error(5); return NULL;}//cannot define requirements twice
                }//->len
            }//passed
            int32 options;
            options=r[0]+(r[1]<<1)+(r[2]<<2)+(r[3]<<3)+(r[4]<<4)+(r[5]<<5);
            //1 bold TTF_STYLE_BOLD
            //2 italic TTF_STYLE_ITALIC
            //4 underline TTF_STYLE_UNDERLINE
            //8 dontblend (blending is the default in 32-bit alpha-enabled modes)
            //16 monospace
            //32 unicode

            bytes=gfs_lof(fh);
            static uint8* content;
            content=(uint8*)malloc(bytes); if (!content){gfs_close(fh); return -1;}
            result=gfs_read(fh,-1,content,bytes);
            gfs_close(fh);
            if (result<0){free(content); return -1;}
           
            //open the font
            //get free font handle
            for (i=32;i<=lastfont;i++){
                if (!font[i]) goto got_font_index;
            }
            //increase handle range
            lastfont++;
            font=(int32*)realloc(font,4*(lastfont+1)); font[lastfont]=NULL;
            fontheight=(int32*)realloc(fontheight,4*(lastfont+1));
            fontwidth=(int32*)realloc(fontwidth,4*(lastfont+1));
            fontflags=(int32*)realloc(fontflags,4*(lastfont+1));
            i=lastfont;
            got_font_index:
            static int32 h;
            h=FontLoad(content,bytes,size,-1,options);
            free(content);
            if (!h) return -1;
           
            font[i]=h;
            fontheight[i]=size;
            fontwidth[i]=FontWidth(h);
            fontflags[i]=options;
            return i;
        }

Many thanks for helping to test and find the issue before others get stuck and lost on it.  Try the process one more time with this code, and let me know if that corrects the issue, or not, for you.  I imagine that it will.  :)

Copy.  Paste.  Purge,  Compile.  Report Back.  ;D
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Fonts are broken
« Reply #9 on: September 12, 2019, 01:54:20 pm »
So this is working right now! Thank you!

I use this last  C code without encoding.
« Last Edit: September 12, 2019, 01:57:58 pm by Petr »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Fonts are broken
« Reply #10 on: September 12, 2019, 01:59:23 pm »
I’m just glad it’s now working as intended.  Many thanks for testing the patch for me.  👍
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Fonts are broken
« Reply #11 on: September 12, 2019, 02:05:58 pm »
I gladly helped. Thank you for the next corrected function!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Fonts are broken
« Reply #12 on: September 12, 2019, 03:12:32 pm »
I write small testing code for all TTF fonts. All working as expected with this upgrade.

Code: QB64: [Select]
  1. 'total test for _FONTWIDTH
  2. REDIM fnt(0) AS STRING
  3.  
  4. Path$ = ENVIRON$("systemroot") + CHR$(92) + "fonts"
  5. c$ = "dir " + Path$ + "\*.ttf /b > fonts.txt"
  6.  
  7. OPEN "fonts.txt" FOR INPUT AS #1
  8.     LINE INPUT #1, f$
  9.     fnt(i) = f$
  10.     i = i + 1
  11.     REDIM _PRESERVE fnt(i) AS STRING
  12. IF i > 0 THEN REDIM _PRESERVE fnt(i - 1) AS STRING
  13.  
  14. FOR t = 0 TO i - 1
  15.     fon = _LOADFONT(fnt(t), 20, "monospace")
  16.     IF _FONTWIDTH(fon) = 0 THEN bug = 1
  17.     _FREEFONT fon
  18. IF bug THEN PRINT "Sorry. Bug found." ELSE PRINT "All pass"
  19.  

Offline Bert22306

  • Forum Regular
  • Posts: 206
    • View Profile
Re: Fonts are broken
« Reply #13 on: September 13, 2019, 04:57:01 am »
Thanks, Steve, thanks, Petr. All works. Petr's test freaked me out, because initially I got only a black screen. Then "all pass." Whew.