1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-25 22:05:53 +00:00
QB64-PE/internal/c/parts/video/font/ttf/src.c
Luke Ceddia 976f757c2f Fix memory leak in _PRINTSTRING
FontRenderTextUTF32 now frees the 'render' array, which is allocated for multi-character strings.
2016-01-28 13:58:08 +11:00

332 lines
8.4 KiB
C

//[ ]what if no glyph index could be found and it returns 0??
//[ ]FT_Done_Face
//[ ]Check for memory leaks
#ifndef DEPENDENCY_LOADFONT
//Stubs
int32 FontRenderTextUTF32(int32 i,uint32*codepoint,int32 codepoints,int32 options,
uint8**out_data,int32*out_x,int32 *out_y,int32*out_x_pre_increment,int32*out_x_post_increment){return NULL;}
int32 FontLoad (uint8 *content_original,int32 content_bytes,int32 default_pixel_height,int32 which_font,int32 options){return NULL;}
int32 FontRenderTextASCII(int32 i,uint8*codepoint,int32 codepoints,int32 options,
uint8**out_data,int32*out_x,int32 *out_y,int32*out_x_pre_increment,int32*out_x_post_increment){return NULL;}
int32 FontWidth(int32 i){return NULL;}
void FontFree(int32 i){return;}
#else
#ifdef QB64_BACKSLASH_FILESYSTEM
#include "src\\freetypeamalgam.h"
#else
#include "src/freetypeamalgam.h"
#endif
FT_Library ft_library;
struct fonts_struct{
uint8 in_use;
uint8 *ttf_data;
int32 default_pixel_height;
uint8 bold;
uint8 italic;
uint8 underline;
uint8 monospace;
int32 monospace_width;
uint8 unicode;
//---------------------------------
FT_Face handle;
int32 baseline;
float default_pixel_height_scale;
};
fonts_struct *fonts=(fonts_struct*)malloc(1);
int32 fonts_last=0;
struct fonts_render_struct{
uint8 *data;
int32 w;
int32 ox;
};
//Master rendering routine (to be called by all other functions)
int32 FontRenderTextUTF32(int32 i,uint32*codepoint,int32 codepoints,int32 options,
uint8**out_data,int32*out_x,int32 *out_y,int32*out_x_pre_increment,int32*out_x_post_increment){
//Notes:
// returns: success{1}/failure{0}
// options: 1=black{0}&white{255}
// out_x_increment: the ideal amount to move across horizontally after drawing the text
// out_data: alpha values for each pixel of the font
if (codepoints<=0){
*out_data=NULL;
*out_x=0;
*out_y=fonts[i].default_pixel_height;
*out_x_pre_increment=0;
*out_x_post_increment=0;
if (codepoints<0) return 0;
return 1;
}
static int32 monochrome;
monochrome=options&1;
static int32 codepoint_w;
static int32 codepoint_i,codepoint_ox;
static uint32 codepoint_value;
static fonts_render_struct *render;
static int32 value;
static uint8 *data1,*data2;
static int w1,h1,ox,oy; //Note: Must be 'int' type
static int32 w2,h2,ox2,oy2;
static int32 x1,y1;
static int32 x2,y2;
if (codepoints>1){
render=(fonts_render_struct*)malloc(sizeof(fonts_render_struct)*codepoints);
}
codepoint_w=0;
codepoint_ox=0;
for (codepoint_i=0;codepoint_i<codepoints;codepoint_i++){
codepoint_value=codepoint[codepoint_i];
static int32 glyph_index;
glyph_index=FT_Get_Char_Index(fonts[i].handle,codepoint_value);
if (!glyph_index){
//failed!
}
if (FT_Load_Glyph(fonts[i].handle,glyph_index,FT_LOAD_DEFAULT)){
//failed!
}
if (monochrome){
if(FT_Render_Glyph(fonts[i].handle->glyph, FT_RENDER_MODE_MONO)){
//failed!
}
}else{
if(FT_Render_Glyph(fonts[i].handle->glyph, FT_RENDER_MODE_NORMAL)){
//failed!
}
}
static int32 pitch1;
pitch1=fonts[i].handle->glyph->bitmap.pitch;
ox=fonts[i].handle->glyph->bitmap_left;
oy=0;
h1=fonts[i].handle->glyph->bitmap.rows;
w1=fonts[i].handle->glyph->bitmap.width;
data1=(uint8*)fonts[i].handle->glyph->bitmap.buffer;
h2=fonts[i].default_pixel_height;
w2=fonts[i].handle->glyph->advance.x/64;//default width
if (w2<w1) w2=w1;
ox2=0;
if (ox>0){
if ((w1+ox)>w2) w2=w1+ox;
ox2=ox;
}
if (ox<0){//compensate for loss of width from left shift
w2=w2+(-ox);
}
//Monospace resize as necessary
if (fonts[i].monospace){
if (w2!=fonts[i].monospace_width){
w2=fonts[i].monospace_width;
ox=0;//no repositioning possible
ox2=w2/2-w1/2;//align to centre
}
}
data2=(uint8*)calloc(w2*h2,1);
oy2=fonts[i].baseline - fonts[i].handle->glyph->bitmap_top;
for (y1=0;y1<h1;y1++){
y2=y1+oy2;
if ((y2>=0)&&(y2<h2)){
for (x1=0;x1<w1;x1++){
x2=x1+ox2;
if ((x2>=0)&&(x2<w2)){
if (monochrome){
data2[x2+y2*w2] = (( data1[y1*pitch1 + x1/8] >> (7-(x1&7)) )&1) * 255;//1-bit
}else{
data2[x2+y2*w2]=data1[x1+y1*pitch1];//8-bit
}
}
}//x1
}
}//y1
//single character render?
if (codepoints==1){
*out_data=data2;
*out_x=w2;
*out_y=h2;
if (ox<0) *out_x_pre_increment=ox; else *out_x_pre_increment=0;
*out_x_post_increment=0;
return 1;
}
if (codepoint_i==0){
if (ox<0){
*out_x_pre_increment=ox;
}else{
*out_x_pre_increment=0;
}
}else{
if (ox<0){//regress codepoint_ox?
if ((codepoint_ox+ox)>=0){
codepoint_ox+=ox;
}else{
codepoint_ox=0;
}
}
}
render[codepoint_i].data=data2;
render[codepoint_i].w=w2;
render[codepoint_i].ox=codepoint_ox;
codepoint_ox+=w2;
if (codepoint_ox>codepoint_w) codepoint_w=codepoint_ox;
}//codepointi loop
//join&'blend' multiple codepoints
w2=codepoint_w; h2=fonts[i].default_pixel_height;
data2=(uint8*)calloc(w2*h2,1);
for (codepoint_i=0;codepoint_i<codepoints;codepoint_i++){
data1=render[codepoint_i].data;
w1=render[codepoint_i].w;
h1=h2;
ox2=render[codepoint_i].ox;
for (y1=0;y1<h1;y1++){
y2=y1;
for (x1=0;x1<w1;x1++){
x2=x1+ox2;
value=data1[x1+y1*w1];
if (value>data2[x2+y2*w2]) data2[x2+y2*w2]=value;
}//x1
}//y1
free(data1);
}//codepoint_i
*out_data=data2;
*out_x=w2;
*out_y=h2;
//Note: '*out_x_pre_increment' is set above
*out_x_post_increment=0;
if (codepoints > 1) free(render);
return 1;
}
int32 FontLoad (uint8 *content_original,int32 content_bytes,int32 default_pixel_height,int32 which_font,int32 options){
static int32 ft_init_called=0;
if (!ft_init_called){
ft_init_called=1;
if (FT_Init_FreeType(&ft_library )) exit(5633);
}
if (which_font==-1) which_font=0;
// options: 1=bold, 2=italic, 4=underline, 8=IGNORED, 16=monospace, 32=unicode
//get new index
static int32 i;
for (i=1;i<=fonts_last;i++){
if (!fonts[i].in_use){
goto got_index;
}
}//i
fonts_last++;
i=fonts_last;
fonts=(fonts_struct*)realloc(fonts,sizeof(fonts_struct)*(fonts_last+1));
fonts[i].in_use=0;
got_index:
memset(&fonts[i],0,sizeof(fonts_struct));
//duplicate content
static uint8* content;
content=(uint8*)malloc(content_bytes);
memcpy(content,content_original,content_bytes);
fonts[i].ttf_data=content;
if (FT_New_Memory_Face(ft_library,content,content_bytes,which_font,&fonts[i].handle)) return 0;
//Note: "Note that you must not deallocate the memory before calling FT_Done_Face."
if (FT_Set_Pixel_Sizes(fonts[i].handle,0,default_pixel_height)){FT_Done_Face(fonts[i].handle); return 0;}
fonts[i].default_pixel_height=default_pixel_height;
/*
static float m_height; m_height=((float)fonts[i].handle->size->metrics.height)/64.0;
static float m_up; m_up=((float)fonts[i].handle->size->metrics.ascender)/64.0;
static float m_down; m_down=-(((float)fonts[i].handle->size->metrics.descender)/64.0);
static float m_char_height; m_char_height=m_up+m_down;
static float m_h; m_h=default_pixel_height;
fonts[i].baseline= (m_h/m_height) * ((m_height-m_char_height)/2.0+m_up) ;
*/
static float m_height; m_height=((float)fonts[i].handle->size->metrics.height)/64.0;
static float m_up; m_up=((float)fonts[i].handle->size->metrics.ascender)/64.0;
static float m_h; m_h=default_pixel_height;
fonts[i].baseline=qbr((m_up/m_height) * m_h);
if (options&16){
//get the width of capital W
static uint32 cp;
cp=87;
static uint8 *data1;
int32 w1,h1,pre_x,post_x;
FontRenderTextUTF32(i,&cp,1,1,&data1,&w1,&h1,&pre_x,&post_x);
fonts[i].monospace_width=w1;
free(data1);
fonts[i].monospace=1;
}//monospace
//Note: DO NOT ADD NEW CONTENT HERE, ADD IT ABOVE MONOSPACE CHECK
fonts[i].in_use=1;
return i;
}
void FontFree(int32 i) {
FT_Done_Face(fonts[i].handle);
free(fonts[i].ttf_data);
fonts[i].in_use = 0;
}
int32 FontRenderTextASCII(int32 i,uint8*codepoint,int32 codepoints,int32 options,
uint8**out_data,int32*out_x,int32 *out_y,int32*out_x_pre_increment,int32*out_x_post_increment){
static uint32 *utf32_codepoint;
static int32 retval;
if (codepoints>=1){
utf32_codepoint=(uint32*)malloc(codepoints*4);
static int32 x;
for (x=0;x<codepoints;x++){
utf32_codepoint[x]=codepage437_to_unicode16[codepoint[x]];
}
}
retval=FontRenderTextUTF32(i,utf32_codepoint,codepoints,options,out_data,out_x,out_y,out_x_pre_increment,out_x_post_increment);
if (codepoints>0) free(utf32_codepoint);
return retval;
}
int32 FontWidth(int32 i){
if (fonts[i].monospace) return fonts[i].monospace_width;
return 0;
}
#endif