[HarfBuzz] Problem with Arabic text

Sauron Sauri sauron1666 at yahoo.es
Wed Apr 25 02:59:50 PDT 2012


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;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/harfbuzz/attachments/20120425/b03f8858/attachment.html>


More information about the HarfBuzz mailing list