GLYPH_KEEP* gk_create_keeper(const unsigned max_glyphs,const unsigned max_memory) { GLYPH_KEEP *keeper; funcname = "gk_create_keeper()"; keeper = (GLYPH_KEEP*)_gk_malloc(sizeof(GLYPH_KEEP)); if (!keeper) return 0; keeper->head = 0; keeper->tail = 0; keeper->num_glyphs = 0; keeper->allocated = sizeof(GLYPH_KEEP); keeper->max_glyphs = max_glyphs; keeper->max_memory = max_memory; keeper->first_index = 0; keeper->last_index = 0; keeper->next = 0; keeper->prev = last_keeper; if (last_keeper) last_keeper->next = keeper; if (!first_keeper) first_keeper = keeper; last_keeper = keeper; _gk_install_exit_handler(); _gk_msg("glyph keeper created\n"); return keeper; }
void gk_keeper_debug(const GLYPH_KEEP* const keeper) { GLYPH_INDEX *index; GLYPH_REND *rend; int ni = 0, nr = 0; _gk_msg("GLYPH_KEEP object (address:%p):\n",keeper); if (!keeper) return; _gk_msg(" can keep %d glyphs, currently keeping %d\n",keeper->max_glyphs,keeper->num_glyphs); _gk_msg(" can use %d bytes of memory, now using %d bytes\n",keeper->max_memory,keeper->allocated); for (index=keeper->first_index;index;index=index->next) { ni++; for (rend=index->first_renderer;rend;rend=rend->next_for_same_index) nr++; } _gk_msg(" this keeper has %d GLYPH_INDEX objects, used by %d renderers\n",ni,nr); }
void gk_done_keeper(GLYPH_KEEP* const keeper) { int mem; if (!keeper) return; while (keeper->head) _gk_unload_glyph(keeper->head); while (keeper->first_index) _gk_glyph_index_done(keeper->first_index); if (keeper==first_keeper) first_keeper = keeper->next; if (keeper==last_keeper) last_keeper = keeper->prev; if (keeper->next) keeper->next->prev = keeper->prev; if (keeper->prev) keeper->prev->next = keeper->next; mem = keeper->allocated - sizeof(GLYPH_KEEP); _gk_free(keeper); _gk_msg("glyph keeper destroyed, (%d bytes leak)\n",mem); }
/* * Renders a glyph immediately, then tries to puts it into cache. * rend and rend->face must be not 0 */ static GLYPH* _gk_rend_workout(GLYPH_REND* const rend,const unsigned unicode) { unsigned glyph_index; int bmp_size; int error; int center_x = 0,center_y = 0; FT_Glyph ft_glyph = 0; GLYPH* glyph; GLYPH_FACE* actual_face; unsigned actual_code; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log,"_gk_rend_workout(%p,%d) begin\n",(void*)rend,unicode); #endif CARE(rend && rend->face); CARE(unicode > 0); CARE(unicode <= GK_MAX_UNICODE); funcname = "_gk_rend_workout()"; _gk_find_mapping(rend->face,unicode,&actual_face,&actual_code); if (!actual_face || !actual_code) return 0; if (!actual_face->face) return 0; glyph_index = FT_Get_Char_Index(actual_face->face,actual_code); if (!glyph_index) { if (unicode==rend->undefined_char || unicode==rend->error_char) return 0; else return _gk_rend_render(rend,rend->undefined_char); } #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," glyph_index is %u\n",glyph_index); #endif /* Preparing for glyph loading: setting size */ /*FT_Activate_Size(size);*/ if (actual_face == rend->face) { error = (rend->size == 0); if (!error) actual_face->face->size = rend->size; } else { error = (actual_face->own_size == 0); if (!error) { actual_face->face->size = actual_face->own_size; error = FT_Set_Char_Size(actual_face->face,rend->hsize,rend->vsize,72,72); } } #ifdef GLYPH_LOG if (error) { if (glyph_log) fprintf(glyph_log," Failed to select size\n"); } else { if (glyph_log) fprintf(glyph_log," Size selected successfully\n"); } #endif /* Loading a glyph with FreeType */ if (!error) { error = FT_Load_Glyph(actual_face->face,glyph_index,rend->load_flags); if (error) _gk_msg("Error: %s: FT_Load_Glyph() bugs on glyph (#%d) for character U+%04X\n",funcname,glyph_index,unicode); else { error = (actual_face->face->glyph == 0); if (error) _gk_msg("Error: %s: Empty glyph slot after FT_Load_Glyph()\n",funcname); } /*#ifdef GLYPH_LOG if (error) { if (glyph_log) fprintf(glyph_log," Could not load a glyph with FT_Load_Glyph()\n"); } else { if (glyph_log) fprintf(glyph_log," Loaded a glyph with FT_Load_Glyph()\n"); } #endif*/ } /* Getting center coordinates (MEGA-HACK) */ /* This whole idea should be re-made in more optimal way */ if (!error) { /*#ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Getting a center point\n"); #endif*/ FT_Glyph g = 0; error = FT_Get_Glyph(actual_face->face->glyph, &g); /*#ifdef GLYPH_LOG if (glyph_log) { if (error) fprintf(glyph_log," FT_Get_Glyph() failed\n"); else fprintf(glyph_log," FT_Get_Glyph() succeeded\n"); if (g) fprintf(glyph_log," FT_Get_Glyph() returned not 0\n"); else fprintf(glyph_log," FT_Get_Glyph() returned 0\n"); } #endif*/ error = error || !g; if (!error && g->format==FT_GLYPH_FORMAT_OUTLINE) { /*#ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Calling FT_Glyph_To_Bitmap()\n"); #endif*/ error = FT_Glyph_To_Bitmap(&g,rend->render_mode,0,1); /*#ifdef GLYPH_LOG if (glyph_log) { if (error) fprintf(glyph_log," FT_Glyph_To_Bitmap() failed\n"); else fprintf(glyph_log," FT_Glyph_To_Bitmap() succeeded\n"); } #endif*/ if (!error) { center_x = 64 * ((FT_BitmapGlyph)g)->left + 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2; center_y = 64 * ((FT_BitmapGlyph)g)->top - 64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2; /*center_x = 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2; center_y = -64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;*/ } } if (g) { /*#ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Calling FT_Done_Glyph()\n"); #endif*/ FT_Done_Glyph(g); } /*#ifdef GLYPH_LOG if (glyph_log) { if (error) fprintf(glyph_log," Could not find a center point\n"); else fprintf(glyph_log," Computed a center point\n"); } #endif*/ } /* Emboldening the glyph */ if (!error) { if (rend->bold_strength && actual_face->face->glyph->format==FT_GLYPH_FORMAT_OUTLINE) { int xstr, ystr, xstr2, ystr2; int xmin,xmax,ymin,ymax; int center_dx, center_dy; FT_GlyphSlot slot = actual_face->face->glyph; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," Emboldening the glyph by %d\n",rend->bold_strength); #endif xstr = rend->bold_strength * FT_MulFix( actual_face->face->units_per_EM, actual_face->face->size->metrics.y_scale ) / 2400; ystr = xstr; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xstr = %d, ystr = %d\n",xstr,ystr); #endif GK_Outline_Embolden(&slot->outline,xstr,&xmin,&xmax,&ymin,&ymax); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xmin = %d, xmax = %d\n",xmin,xmax); if (glyph_log) fprintf(glyph_log," ymin = %d, ymax = %d\n",ymin,ymax); #endif /*xstr = xstr * 2; ystr = xstr;*/ #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xstr = %d, ystr = %d\n",xstr,ystr); #endif xstr2 = xmin+xmax; ystr2 = ymin+ymax; #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," xstr2 = %d, ystr2 = %d\n",xstr2,ystr2); if (glyph_log) fprintf(glyph_log," xscale = %.5f\n",((double)actual_face->face->size->metrics.x_scale)/65536); if (glyph_log) fprintf(glyph_log," yscale = %.5f\n",((double)actual_face->face->size->metrics.y_scale)/65536); #endif if (slot->advance.x) slot->advance.x += xstr; if (slot->advance.y) slot->advance.y += ystr; slot->metrics.width += xstr * 2; slot->metrics.height += ystr * 2; /*slot->metrics.horiBearingX -= xmin;*/ slot->metrics.horiBearingY += ystr * 2; slot->metrics.horiAdvance += xstr * 2; slot->metrics.vertBearingX -= xstr; slot->metrics.vertBearingY += ystr * 2; slot->metrics.vertAdvance += ystr * 2; /*center_dx = (int)( (double)xstr / 2 * (double)actual_face->face->size->metrics.x_scale / (80000) ); center_dy = (int)( (double)ystr / 2 * (double)actual_face->face->size->metrics.y_scale / (65536) );*/ center_dx = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.x_ppem / 80); center_dy = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.y_ppem / 80); #ifdef GLYPH_LOG if (glyph_log) fprintf(glyph_log," center_x += %.1f\n",((double)center_dx)/64); if (glyph_log) fprintf(glyph_log," center_y += %.1f\n",((double)center_dx)/64); #endif center_x += center_dx; center_y += center_dy; /*center_x += xstr;*/ /*center_y += ymin;*/ /*FT_GlyphSlot_Embolden(slot);*/ } } /* Getting a glyph from FreeType */ if (!error) { error = FT_Get_Glyph(actual_face->face->glyph, &ft_glyph); error = error || !ft_glyph; if (error) _gk_msg("Error: %s: Can't get a glyph with FT_Get_Glyph() call. Glyph (#%d) for character U+%04X\n", funcname,glyph_index,unicode); } /* Transforming the glyph to apply rotation and italics */ if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE && rend->do_matrix_transform) { error = FT_Glyph_Transform(ft_glyph,&rend->matrix,0); if (!error) { FT_Vector c; c.x = center_x; c.y = center_y; FT_Vector_Transform(&c,&rend->matrix); center_x = c.x; center_y = c.y; } } /* Converting glyph to bitmap */ if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE) { error = FT_Glyph_To_Bitmap(&ft_glyph,rend->render_mode,0,1); if (error) _gk_msg("Error: %s: FT_Glyph_To_Bitmap() bugs on character U+%04X\n",funcname,unicode); } /* Checking if we have bitmap now */ if (!error) { error = (ft_glyph->format!=FT_GLYPH_FORMAT_BITMAP); if (error) _gk_msg("Error: %s: Glyph is not FT_GLYPH_FORMAT_BITMAP after rendering with FT_Glyph_To_Bitmap()\n",funcname); } #ifdef GLYPH_LOG /* { if (glyph_log) { fprintf(glyph_log," We got a bitmap glyph from FreeType!\n"); if (ft_glyph->format==FT_GLYPH_FORMAT_BITMAP) { fprintf(glyph_log," Format: FT_GLYPH_FORMAT_BITMAP\n"); fprintf(glyph_log," Size: %dx%d, pitch: %d\n", ((FT_BitmapGlyph)ft_glyph)->bitmap.width, ((FT_BitmapGlyph)ft_glyph)->bitmap.rows, ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch); if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_MONO) { int x,y; int pitch = ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch; fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_MONO\n"); fprintf(glyph_log," Buffer:\n"); for (y=0; y < ((FT_BitmapGlyph)ft_glyph)->bitmap.rows; y++) { fprintf(glyph_log," "); for (x=0; x < ((FT_BitmapGlyph)ft_glyph)->bitmap.width; x++) { unsigned char byte = ((unsigned char*)((FT_BitmapGlyph)ft_glyph)->bitmap.buffer)[y*pitch+x]; unsigned char mask = 128 >> (x%8); fprintf(glyph_log,"%s",(byte&mask)?" *":" ."); } fprintf(glyph_log,"\n"); } } else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_GRAY\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY2) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_GRAY2\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY4) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_GRAY4\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_LCD\n"); else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD_V) fprintf(glyph_log," Pixel mode: FT_PIXEL_MODE_LCD_V\n"); } else if (ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE) { fprintf(glyph_log," Format: FT_GLYPH_FORMAT_OUTLINE\n"); } fprintf(glyph_log," Advance: ( %.1f , %.1f ) pixels\n", ((double)ft_glyph->advance.x)/0x10000,((double)ft_glyph->advance.y)/0x10000); } }*/ #endif if (!error) { error = ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch < 0 ); if (error) _gk_msg("Error: rend_workout(): Rendered glyph has negative pitch value, can't handle\n"); /* FIXME */ } if (!error) { glyph = (GLYPH*)_gk_malloc(sizeof(GLYPH)); error = (glyph == 0); } if (error || !ft_glyph) { if (ft_glyph) FT_Done_Glyph(ft_glyph); if (unicode==rend->error_char) return 0; else return _gk_rend_render(rend,rend->error_char); } glyph->unicode = unicode; glyph->width = ((FT_BitmapGlyph)ft_glyph)->bitmap.width; glyph->height = ((FT_BitmapGlyph)ft_glyph)->bitmap.rows; glyph->left = ((FT_BitmapGlyph)ft_glyph)->left; glyph->top = ((FT_BitmapGlyph)ft_glyph)->top; glyph->advance_x = ft_glyph->advance.x >> 10; glyph->advance_y = ft_glyph->advance.y >> 10; glyph->center_x = (center_x + 31) / 64; glyph->center_y = (center_y + 31) / 64; glyph->index = 0; glyph->prev = 0; glyph->next = 0; glyph->bmp = 0; glyph->bmpsize = 0; _gk_msg("rendering character '%c'\n",unicode); bmp_size = glyph->width*glyph->height; if (!bmp_size) /* empty glyph, like space (' ') character */ { if (rend->index) _gk_glyph_index_add_glyph(rend->index,glyph); FT_Done_Glyph(ft_glyph); return glyph; } if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { #ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK int pitch1 = (glyph->width+7)>>3; int bitpack_size = glyph->height*pitch1; #ifdef GLYPH_TARGET_KNOWS_MONO_RLE7 int rle_size = 0; if (rend->index) rle_size = _gk_make_RLE7( ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer, glyph->width, glyph->height, ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch); if (rle_size>0 && rle_size<=bitpack_size) { glyph->bmp = (unsigned char*)_gk_malloc(rle_size); if (!glyph->bmp) { _gk_free(glyph); return 0; } memcpy(glyph->bmp,rle_buffer,rle_size); glyph->bmpsize = rle_size; } else #endif /* GLYPH_TARGET_KNOWS_MONO_RLE7 */ { glyph->bmp = (unsigned char*)_gk_malloc(bitpack_size+1); if (!glyph->bmp) { _gk_free(glyph); return 0; } glyph->bmp[0] = GLYPH_MONO_BITPACK; if ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch == pitch1 ) memcpy( glyph->bmp+1, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer, bitpack_size ); else { unsigned char *d = glyph->bmp+1; int y = 0; for (; y<glyph->height; y++,d+=pitch1) memcpy( d, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch, pitch1 ); } glyph->bmpsize = bitpack_size+1; } #else /* GLYPH_TARGET_KNOWS_MONO_BITPACK */ { int y = 0; unsigned char* b; glyph->bmp = (unsigned char*)_gk_malloc(bmp_size+1); if (!glyph->bmp) { _gk_free(glyph); return 0; } glyph->bmp[0] = GLYPH_UNCOMPRESSED; glyph->bmpsize = bmp_size+1; b = glyph->bmp + 1; for (; y<glyph->height; y++) { int x = 0; unsigned char* a = ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch; while (x<glyph->width) { if (x < glyph->width) { *b++ = *a&0x80 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x40 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x20 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x10 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x08 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x04 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x02 ? 255 : 0; x++; } if (x < glyph->width) { *b++ = *a&0x01 ? 255 : 0; x++; } a++; } } } #endif /* GLYPH_TARGET_KNOWS_MONO_BITPACK */ }