<html><body><div style="color:#000; background-color:#fff; font-family:times new roman, new york, times, serif;font-size:10pt"><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><meta http-equiv="content-type" content="text/html; charset=utf-8"><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; ">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. </span></div><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><br></span></div><div style="font-size: 10pt; "><span
class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; ">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.</span><br></div><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><br>Below is the source code that render a unicode texts and draw them on screen with SGE and SDL libraries.</span></div><div style="font-size: 10pt; "><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif"><br></font></div><div style="font-size: 10pt; "><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif">Uint16 *text is the text. It's converted to unicode with iconv utility.</font></div><div
style="font-size: 10pt; "><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif"><br></font></div><div style="font-size: 10pt; "><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif">In the code below I see three problems:</font></div><div style="font-size: 10pt; "><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif"><br></font></div><div style="font-size: 10pt; "><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif">First problem: </font><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><i>sge_TTF_RenderUNICODE</i> function find the char glyphs always from left to right. </span><br></div><div style="font-size: 10pt; "><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif"><br></font></div><div><span class="Apple-style-span" style="font-family:
verdana, geneva, helvetica, arial, sans-serif; font-size: 10pt; ">Second problem: </span><i style="font-family: verdana, geneva, helvetica, arial, sans-serif; font-size: 10pt; ">Find_Glyph </i><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2">funcion calls</font><i style="font-family: verdana, geneva, helvetica, arial, sans-serif; font-size: 10pt; "> TT_Char:_Index</i><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2"> function to get a unicode character bitmap, but in Arabic the glyph is different depending on the position.</font></div><div><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2"><br></font></div><div><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2">What are my options?</font></div><div><font class="Apple-style-span" face="verdana, geneva, helvetica, arial,
sans-serif" size="2">Can I use harfbuzz library to obtain the glyph indexes ordered and load them with TT_Load_Glyph function? </font></div><div><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2">If yes, is there a sample code of how can I do it?</font></div><div><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2"><br></font></div><div><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2"><br></font></div><div><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif" size="2">Here is the source code of my application:</font></div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div style="font-size: 10pt; "><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><br></span></div><meta http-equiv="content-type" content="text/html;
charset=utf-8"><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><i>//================================================================================== <br>// TT Render (unicode) <br>// Returns an 8bit or 32bit(8/8/8/8-alpha) surface with TT text <br>//================================================================================== <br>SDL_Surface *sge_TTF_RenderUNICODE(sge_TTFont *font,const Uint16 *text, SDL_Color fg, SDL_Color bg) <br>{ <br> int xstart, width; <br> int w, h; <br> SDL_Surface *textbuf; <br> SDL_Palette *palette; <br> int index; <br> int rdiff, gdiff, bdiff; <br>
const Uint16 *ch; <br> Uint8 *src, *dst; <br> Uint32 *dst32; <br> int row, col; <br> TT_Error error; <br><br> sge_TTF_FitToBox_UNI( font, text ); <br><br> /* Get the dimensions of the text surface */ <br> SDL_Rect ret=sge_TTF_TextSize_UNI(font, text); <br> </i></span></div><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><i><span class="Apple-tab-span" style="white-space:pre"> </span>/*</i></span></div><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><span class="Apple-style-span" style="font-family:
verdana, geneva, helvetica, arial, sans-serif; "><i><span class="Apple-tab-span" style="white-space:pre"> </span>Here do things with SDL. I remove code because is not important and to simply it.</i></span></div><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><i><span class="Apple-tab-span" style="white-space:pre"> </span>*/<br> /* Load and render each character */ <br> // start drawing in the left-most pixel! <br> // otherwise text width calculated to fit the box will be overriden! <br> xstart = 0; <br><br> for ( ch=text; *ch; ++ch ) { <br> error = Find_Glyph(font, *ch); //Find and Load the
glyph <br> if ( ! error ) { <br> w = font->current->pixmap.width; <br> src = (Uint8 *)font->current->pixmap.bitmap; <br> for ( row = 0; row < h; ++row ) { <br> dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch + xstart + font->current->minx; <br> <br>
switch(_sge_TTF_AA){ <br> <br> case 0:{ /* Normal */ <br> for ( col=w; col>0; col -= 4 ) { <br> *dst++ |= (*src++<3)? 0:1; <br>
*dst++ |= (*src++<3)? 0:1; <br> *dst++ |= (*src++<3)? 0:1; <br> *dst++ |= (*src++<3)? 0:1; <br> } <br> } <br>
break; <br> case 1:{ /* Antialiasing */ <br> for ( col=w; col>0; col -= 4 ) { <br> *dst++ |= *src++; <br> *dst++ |= *src++; <br>
*dst++ |= *src++; <br> *dst++ |= *src++; <br> } <br> } <br> break; <br>
<br> case 2:{ /* Alpha */ <br> dst32 = (Uint32 *)textbuf->pixels + row * textbuf->pitch/4 + xstart + font->current->minx; <br> for ( col=w; col>0; col -= 4 ) { <br> *dst32++ |= ctab[*src++]; <br>
*dst32++ |= ctab[*src++]; <br> *dst32++ |= ctab[*src++]; <br> *dst32++ |= ctab[*src++]; <br> } <br>
} <br> break; <br> } <br> } <br> xstart += font->current->advance; <br> if ( font->style & SGE_TTF_BOLD ) { <br> xstart += font->glyph_overhang; <br> } <br>
} <br> } <br> /* Handle the underline style */ <br> if ( font->style & SGE_TTF_UNDERLINE ) { <br> int row_offset; <br><br> row_offset = round(font->ascent) + 1; <br> if ( row_offset > font->height ) { <br> row_offset = font->height-1; <br> } <br><br> if(_sge_TTF_AA==0){ <br> memset((Uint8 *)textbuf->pixels+row_offset*textbuf->pitch, 1, width); <br>
}else if(_sge_TTF_AA==1){ <br> memset((Uint8 *)textbuf->pixels+row_offset*textbuf->pitch, 4, width); <br> }else{ <br> dst32 = (Uint32 *)textbuf->pixels+row_offset*textbuf->pitch/4; <br> for ( col=width; col > 0; --col ) { <br> *dst32++ = ctab[4]; <br> } <br> } <br>
<br> } <br> return(textbuf); <br>} <br><br>//================================================================================== <br>// Find glyph <br>//================================================================================== <br>TT_Error Find_Glyph(sge_TTFont *font, Uint16 ch) <br>{ <br> int retval; <br><br> retval = 0; <br> if ( ch < 256 ) { <br> font->current = &font->cache[ch]; <br> } else { <br> if ( font->scratch.cached != ch ) { <br>
Flush_Glyph(&font->scratch); <br> } <br> font->current = &font->scratch; <br> } <br> if ( ! font->current->cached ) { <br> retval = Load_Glyph(font, ch, font->current); <br> } <br> return retval; <br>} <br></i></span></div><div style="font-family: 'times new roman', 'new york', times, serif; font-size: 10pt; "><span class="Apple-style-span" style="font-family: verdana, geneva, helvetica, arial, sans-serif; "><i><br></i></span></div><div><span><font class="Apple-style-span" face="verdana, geneva, helvetica, arial, sans-serif"
size="2"><i><div>//==================================================================================</div><div>// Prepare for the most ugliest code in SGE!</div><div>// Don't hate me! Sam wrote this!!</div><div>//==================================================================================</div><div>TT_Error Load_Glyph(sge_TTFont *font, Uint16 ch, struct glyph *glyph)</div><div>{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_UShort index;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Glyph_Metrics metrics;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Outline outline;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int x_offset;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int y_offset;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Error error;</div><div><br></div><div><span
class="Apple-tab-span" style="white-space:pre"> </span>/* Load the glyph */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>index = TT_Char_Index(font->map, UNICODE(ch));</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>error = TT_Load_Glyph(font->inst, font->glyph, index, TTLOAD_DEFAULT);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( error ) return error;</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* Get the bounding box */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Get_Glyph_Metrics(font->glyph, &metrics);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->minx = (metrics.bbox.xMin & -64) / 64;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->maxx = ((metrics.bbox.xMax + 63) & -64) / 64;</div><div><span
class="Apple-tab-span" style="white-space:pre"> </span>glyph->miny = (metrics.bbox.yMin & -64) / 64;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->maxy = ((metrics.bbox.yMax + 63) & -64) / 64;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->advance = (metrics.advance & -64) / 64;</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* Adjust for bold and italic text */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( font->style & SGE_TTF_BOLD ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->maxx += font->glyph_overhang;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( font->style & SGE_TTF_ITALIC ) {</div><div><span class="Apple-tab-span"
style="white-space:pre"> </span>glyph->maxx += round(font->glyph_italics);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* Get the bitmap memory */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.width = ((glyph->maxx - glyph->minx) + 7) & ~7;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.rows = font->height;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.cols = glyph->bitmap.width/8;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.flow = TT_Flow_Down;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.size = (glyph->bitmap.rows * glyph->bitmap.cols);</div><div><span class="Apple-tab-span" style="white-space:pre">
</span>if ( glyph->bitmap.size ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.bitmap = malloc(glyph->bitmap.size);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( ! glyph->bitmap.bitmap ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>error = TT_Err_Out_Of_Memory;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>goto was_error;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>memset(glyph->bitmap.bitmap, 0, glyph->bitmap.size);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} else {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.bitmap = 0;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><br></div><div><span
class="Apple-tab-span" style="white-space:pre"> </span>/* Get the pixmap memory */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.width = ((glyph->maxx - glyph->minx) + 3) & ~3;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.rows = font->height;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.cols = glyph->pixmap.width;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.flow = TT_Flow_Down;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.size = (glyph->pixmap.rows * glyph->pixmap.cols);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( glyph->pixmap.size ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.bitmap = malloc(glyph->pixmap.size);</div><div><span
class="Apple-tab-span" style="white-space:pre"> </span>if ( ! glyph->pixmap.bitmap ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>error = TT_Err_Out_Of_Memory;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>goto was_error;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>memset(glyph->pixmap.bitmap, 0, glyph->pixmap.size);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>} else {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.bitmap = 0;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* Render the glyph into the bitmap and pixmap */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>error =
TT_Get_Glyph_Outline(font->glyph, &outline);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* Handle the italic style */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( font->style & SGE_TTF_ITALIC ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Matrix shear;</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>shear.xx = 1<<16;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>shear.xy = (int)(font->glyph_italics*(1<<16))/font->height;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>shear.yx = 0;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>shear.yy = 1<<16;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Transform_Outline(&outline, &shear);</div><div><span class="Apple-tab-span"
style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>x_offset = -glyph->minx * 64;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>y_offset = -round(font->descent) * 64;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Translate_Outline(&outline, x_offset, y_offset);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>error += TT_Get_Outline_Bitmap(engine, &outline, &glyph->bitmap);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>error += TT_Get_Outline_Pixmap(engine, &outline, &glyph->pixmap);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* Handle the bold style */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( font->style & SGE_TTF_BOLD ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int row,
col;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int offset;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int pixel;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Uint8 *pixmap;</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* The bitmap is easy, just render another copy */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for ( offset=0; offset < font->glyph_overhang; ++offset ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Translate_Outline(&outline, 64, 0);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>error += TT_Get_Outline_Bitmap(engine,</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>
&outline,&glyph->bitmap);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>x_offset += font->glyph_overhang*64;</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* The pixmap is a little harder, we have to add and clamp */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for ( row=glyph->pixmap.rows-1; row >= 0; --row ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>pixmap = (Uint8 *)glyph->pixmap.bitmap +</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> row*glyph->pixmap.cols;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>for (offset=1; offset<=font->glyph_overhang; ++offset) {</div><div><span class="Apple-tab-span"
style="white-space:pre"> </span>for (col=glyph->pixmap.cols-1; col > 0; --col) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>pixel=(pixmap[col]+pixmap[col-1]);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( pixel > 4 ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>pixel = 4;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>pixmap[col] = (Uint8)pixel;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>TT_Translate_Outline(&outline,
-x_offset, -y_offset);</div><div><br></div><div>//Gotos? Sam, how could you?!</div><div>was_error:</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( error ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( glyph->bitmap.bitmap ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>free(glyph->bitmap.bitmap);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->bitmap.bitmap = 0;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>if ( glyph->pixmap.bitmap ) {</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>free(glyph->pixmap.bitmap);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->pixmap.bitmap = 0;</div><div><span class="Apple-tab-span" style="white-space:pre">
</span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>return error;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>/* We're done, mark this glyph cached */</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>glyph->cached = ch;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>return TT_Err_Ok;</div><div>}</div></i></font></span></div></div></body></html>