I've an application that uses SDL, SGE and Freetype libraries to render text on
Screen. Latin text works fine, but Arabic text appears from left to right.
Arabic is a complex language, is right-to-left and the letters have different
shape depending on their position: initial, medial, terminal, and isolated.
It's possible to use harfbuzz library to obtain the glyph indexes well ordered
and load them with freetype (TT_Load_Glyph). I need use this because my
application uses SDL and SGE to render texts on screen.
Below is the source code that render a unicode texts and draw them on screen
with SGE and SDL libraries.
Uint16 *text is the text. It's converted to unicode with iconv utility.
In the code below I see three problems:
First problem: sge_TTF_RenderUNICODE function find the char glyphs always from
left to right.
Second problem: Find_Glyph funcion callsTT_Char:_Indexfunction to get a unicode
character bitmap, but in Arabic the glyph is different depending on
the position.
What are my options?
Can I use harfbuzz library to obtain the glyph indexes ordered and load them
with TT_Load_Glyph function?
If yes, is there a sample code of how can I do it?
Here is the source code of my application:
//==================================================================================
// TT Render (unicode)
// Returns an 8bit or 32bit(8/8/8/8-alpha) surface with TT text
//==================================================================================
SDL_Surface *sge_TTF_RenderUNICODE(sge_TTFont *font,const Uint16 *text,
SDL_Color fg, SDL_Color bg)
{
int xstart, width;
int w, h;
SDL_Surface *textbuf;
SDL_Palette *palette;
int index;
int rdiff, gdiff, bdiff;
const Uint16 *ch;
Uint8 *src, *dst;
Uint32 *dst32;
int row, col;
TT_Error error;
sge_TTF_FitToBox_UNI( font, text );
/* Get the dimensions of the text surface */
SDL_Rect ret=sge_TTF_TextSize_UNI(font, text);
/*
Here do things with SDL. I remove code because is not important and to simply
it.
*/
/* Load and render each character */
// start drawing in the left-most pixel!
// otherwise text width calculated to fit the box will be overriden!
xstart = 0;
for ( ch=text; *ch; ++ch ) {
error = Find_Glyph(font, *ch); //Find and Load the glyph
if ( ! error ) {
w = font->current->pixmap.width;
src = (Uint8 *)font->current->pixmap.bitmap;
for ( row = 0; row < h; ++row ) {
dst = (Uint8 *)textbuf->pixels + row *
textbuf->pitch + xstart + font->current->minx;
switch(_sge_TTF_AA){
case 0:{ /* Normal */
for ( col=w; col>0; col -= 4 )
{
*dst++ |= (*src++<3)?
0:1;
*dst++ |= (*src++<3)?
0:1;
*dst++ |= (*src++<3)?
0:1;
*dst++ |= (*src++<3)?
0:1;
}
}
break;
case 1:{ /* Antialiasing */
for ( col=w; col>0; col -= 4 )
{
*dst++ |= *src++;
*dst++ |= *src++;
*dst++ |= *src++;
*dst++ |= *src++;
}
}
break;
case 2:{ /* Alpha */
dst32 = (Uint32
*)textbuf->pixels + row * textbuf->pitch/4 + xstart + font->current->minx;
for ( col=w; col>0; col -= 4 )
{
*dst32++ |=
ctab[*src++];
*dst32++ |=
ctab[*src++];
*dst32++ |=
ctab[*src++];
*dst32++ |=
ctab[*src++];
}
}
break;
}
}
xstart += font->current->advance;
if ( font->style & SGE_TTF_BOLD ) {
xstart += font->glyph_overhang;
}
}
}
/* Handle the underline style */
if ( font->style & SGE_TTF_UNDERLINE ) {
int row_offset;
row_offset = round(font->ascent) + 1;
if ( row_offset > font->height ) {
row_offset = font->height-1;
}
if(_sge_TTF_AA==0){
memset((Uint8
*)textbuf->pixels+row_offset*textbuf->pitch, 1, width);
}else if(_sge_TTF_AA==1){
memset((Uint8
*)textbuf->pixels+row_offset*textbuf->pitch, 4, width);
}else{
dst32 = (Uint32
*)textbuf->pixels+row_offset*textbuf->pitch/4;
for ( col=width; col > 0; --col ) {
*dst32++ = ctab[4];
}
}
}
return(textbuf);
}
//==================================================================================
// Find glyph
//==================================================================================
TT_Error Find_Glyph(sge_TTFont *font, Uint16 ch)
{
int retval;
retval = 0;
if ( ch < 256 ) {
font->current = &font->cache[ch];
} else {
if ( font->scratch.cached != ch ) {
Flush_Glyph(&font->scratch);
}
font->current = &font->scratch;
}
if ( ! font->current->cached ) {
retval = Load_Glyph(font, ch, font->current);
}
return retval;
}
//==================================================================================
// Prepare for the most ugliest code in SGE!
// Don't hate me! Sam wrote this!!
//==================================================================================
TT_Error Load_Glyph(sge_TTFont *font, Uint16 ch, struct glyph *glyph)
{
TT_UShort index;
TT_Glyph_Metrics metrics;
TT_Outline outline;
int x_offset;
int y_offset;
TT_Error error;
/* Load the glyph */
index = TT_Char_Index(font->map, UNICODE(ch));
error = TT_Load_Glyph(font->inst, font->glyph, index, TTLOAD_DEFAULT);
if ( error ) return error;
/* Get the bounding box */
TT_Get_Glyph_Metrics(font->glyph, &metrics);
glyph->minx = (metrics.bbox.xMin & -64) / 64;
glyph->maxx = ((metrics.bbox.xMax + 63) & -64) / 64;
glyph->miny = (metrics.bbox.yMin & -64) / 64;
glyph->maxy = ((metrics.bbox.yMax + 63) & -64) / 64;
glyph->advance = (metrics.advance & -64) / 64;
/* Adjust for bold and italic text */
if ( font->style & SGE_TTF_BOLD ) {
glyph->maxx += font->glyph_overhang;
}
if ( font->style & SGE_TTF_ITALIC ) {
glyph->maxx += round(font->glyph_italics);
}
/* Get the bitmap memory */
glyph->bitmap.width = ((glyph->maxx - glyph->minx) + 7) & ~7;
glyph->bitmap.rows = font->height;
glyph->bitmap.cols = glyph->bitmap.width/8;
glyph->bitmap.flow = TT_Flow_Down;
glyph->bitmap.size = (glyph->bitmap.rows * glyph->bitmap.cols);
if ( glyph->bitmap.size ) {
glyph->bitmap.bitmap = malloc(glyph->bitmap.size);
if ( ! glyph->bitmap.bitmap ) {
error = TT_Err_Out_Of_Memory;
goto was_error;
}
memset(glyph->bitmap.bitmap, 0, glyph->bitmap.size);
} else {
glyph->bitmap.bitmap = 0;
}
/* Get the pixmap memory */
glyph->pixmap.width = ((glyph->maxx - glyph->minx) + 3) & ~3;
glyph->pixmap.rows = font->height;
glyph->pixmap.cols = glyph->pixmap.width;
glyph->pixmap.flow = TT_Flow_Down;
glyph->pixmap.size = (glyph->pixmap.rows * glyph->pixmap.cols);
if ( glyph->pixmap.size ) {
glyph->pixmap.bitmap = malloc(glyph->pixmap.size);
if ( ! glyph->pixmap.bitmap ) {
error = TT_Err_Out_Of_Memory;
goto was_error;
}
memset(glyph->pixmap.bitmap, 0, glyph->pixmap.size);
} else {
glyph->pixmap.bitmap = 0;
}
/* Render the glyph into the bitmap and pixmap */
error = TT_Get_Glyph_Outline(font->glyph, &outline);
/* Handle the italic style */
if ( font->style & SGE_TTF_ITALIC ) {
TT_Matrix shear;
shear.xx = 1<<16;
shear.xy = (int)(font->glyph_italics*(1<<16))/font->height;
shear.yx = 0;
shear.yy = 1<<16;
TT_Transform_Outline(&outline, &shear);
}
x_offset = -glyph->minx * 64;
y_offset = -round(font->descent) * 64;
TT_Translate_Outline(&outline, x_offset, y_offset);
error += TT_Get_Outline_Bitmap(engine, &outline, &glyph->bitmap);
error += TT_Get_Outline_Pixmap(engine, &outline, &glyph->pixmap);
/* Handle the bold style */
if ( font->style & SGE_TTF_BOLD ) {
int row, col;
int offset;
int pixel;
Uint8 *pixmap;
/* The bitmap is easy, just render another copy */
for ( offset=0; offset < font->glyph_overhang; ++offset ) {
TT_Translate_Outline(&outline, 64, 0);
error += TT_Get_Outline_Bitmap(engine,
&outline,&glyph->bitmap);
}
x_offset += font->glyph_overhang*64;
/* The pixmap is a little harder, we have to add and clamp */
for ( row=glyph->pixmap.rows-1; row >= 0; --row ) {
pixmap = (Uint8 *)glyph->pixmap.bitmap +
row*glyph->pixmap.cols;
for (offset=1; offset<=font->glyph_overhang; ++offset) {
for (col=glyph->pixmap.cols-1; col > 0; --col) {
pixel=(pixmap[col]+pixmap[col-1]);
if ( pixel > 4 ) {
pixel = 4;
}
pixmap[col] = (Uint8)pixel;
}
}
}
}
TT_Translate_Outline(&outline, -x_offset, -y_offset);
//Gotos? Sam, how could you?!
was_error:
if ( error ) {
if ( glyph->bitmap.bitmap ) {
free(glyph->bitmap.bitmap);
glyph->bitmap.bitmap = 0;
}
if ( glyph->pixmap.bitmap ) {
free(glyph->pixmap.bitmap);
glyph->pixmap.bitmap = 0;
}
return error;
}
/* We're done, mark this glyph cached */
glyph->cached = ch;
return TT_Err_Ok;
}_______________________________________________
HarfBuzz mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/harfbuzz