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

Reply via email to