<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>