"Fossies" - the Fresh Open Source Software Archive

Member "yudit-3.0.7/swindow/SFontImpl.cpp" (7 Jun 2020, 19796 Bytes) of package /linux/misc/yudit-3.0.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "SFontImpl.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.5_vs_3.0.7.

    1 /** 
    2  *  Yudit Unicode Editor Source File
    3  *
    4  *  GNU Copyright (C) 1997-2006  Gaspar Sinai <gaspar@yudit.org>  
    5  *
    6  *  This program is free software; you can redistribute it and/or modify
    7  *  it under the terms of the GNU General Public License, version 2,
    8  *  dated June 1991. See file COPYYING for details.
    9  *
   10  *  This program is distributed in the hope that it will be useful,
   11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  *  GNU General Public License for more details.
   14  *
   15  *  You should have received a copy of the GNU General Public License
   16  *  along with this program; if not, write to the Free Software
   17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  */
   19  
   20 #include "swindow/SFontImpl.h"
   21 #include "swindow/SFontTTF.h"
   22 #include "swindow/SFontNative.h"
   23 #include "swindow/SFontBDF.h"
   24 #include "swindow/SUniFont.h"
   25 #include "swindow/SAwt.h"
   26 #include "swindow/SImage.h"
   27 
   28 #include "stoolkit/SIO.h"
   29 #include "stoolkit/SBinHashtable.h"
   30 #include "stoolkit/SHashtable.h"
   31 #include "stoolkit/SExcept.h"
   32 #include "stoolkit/SUtil.h"
   33 #include "stoolkit/SCluster.h"
   34 
   35 static SStringVector fontSearchPath(
   36    "/,fonts,../fonts,/etc/fonts,/usr/share/yudit/fonts");
   37 
   38 
   39 /* it makes a big difference in speed */
   40 
   41 /**
   42  * @author: Gaspar Sinai <gaspar@yudit.org>
   43  * @version: 2000-04-23
   44  * This is the abstract widget toolkit font package
   45  */
   46 
   47 
   48 class SFontDelegate
   49 {
   50 public:
   51   enum SE_Type { SE_NONE, SE_TTF, SE_NATIVE, SE_UNIFONT, SE_BDF };
   52   SFontDelegate (const SFile& file, SE_Type type, 
   53       const SString& encoding=SString(""));
   54   ~SFontDelegate();
   55   unsigned int count;
   56   SE_Type type;
   57   union {
   58    SFontTTF* ttf;
   59    SFontNative* native;
   60    SUniFont* unifont;
   61    SFontBDF* bdf;
   62   } u;
   63 };
   64 
   65 /**
   66  * Create a brand new delegate
   67  */
   68 SFontDelegate::SFontDelegate (const SFile& file, 
   69   SE_Type _type, const SString& enc)
   70 {
   71   count = 1;
   72   type = _type;
   73   u.ttf = 0;
   74   switch (type)
   75   {
   76   case SE_TTF:
   77     u.ttf = new SFontTTF (file, enc);
   78     if (!u.ttf->isOK())
   79     {
   80       delete u.ttf;
   81       u.ttf = 0;
   82       type = SE_NONE;
   83     }
   84     break;
   85   case SE_NATIVE:
   86     u.native = SAwt::getFont(enc);
   87     break;
   88   case SE_UNIFONT:
   89     u.unifont = new SUniFont(file);
   90     break;
   91   case SE_BDF:
   92     u.bdf = new SFontBDF(file);
   93     break;
   94   case SE_NONE:
   95      break;
   96   }
   97 }
   98 
   99 SFontDelegate::~SFontDelegate()
  100 {
  101   switch (type)
  102   {
  103   case SE_TTF:
  104      if (u.ttf!=0) delete u.ttf;
  105      break;
  106   case SE_NATIVE:
  107      if (u.native!=0) delete u.native;
  108      break;
  109   case SE_UNIFONT:
  110      if (u.unifont!=0) delete u.unifont;
  111      break;
  112   case SE_BDF:
  113      if (u.bdf!=0) delete u.bdf;
  114      break;
  115   case SE_NONE:
  116      break;
  117   }
  118 }
  119 
  120 typedef SBinHashtable<SFontDelegate*> SFontCache;
  121 static SFontCache fontCache;
  122 
  123 /**
  124  * Create a new font face.
  125  * @param _name is the logical x11 font descriptor that matches
  126  *        this font.  "-%s-%s-%s-%s-*-%s-%g-*-*-*-%s-%s-%s-%s"
  127  * foundry-family-weight-slant-*-style-pixel-*-*-*-spacing-avgWidth-registry-encoding
  128  * @param encoding is not zero size if there is an external encoder.
  129  */
  130 SFontImpl::SFontImpl (const SString& _name, const SString& _encoding) : 
  131     xlfd (_name), name(_name), encoding (_encoding)
  132 {
  133   /**
  134    * Try to find TTF first
  135    */
  136   rlFont = false;
  137   lrFont = false;
  138   SString decorated (name);
  139   decorated.append ("~");
  140   decorated.append (encoding);
  141   //fprintf (stderr, "XLFD %*.*s\n", SSARGS(xlfd));
  142   SFontDelegate* d = fontCache.get(decorated);
  143   delegate = 0;
  144   if (d!=0)
  145   {
  146     //fprintf (stderr, "resusing %*.*s %u\n", SSARGS(name), d->count);
  147     delegate = d;
  148     d->count++;
  149     if (d->type == SFontDelegate::SE_NATIVE)
  150     {
  151       createSaneXLFD();
  152     }
  153   }
  154   else
  155   {
  156     //n.append (".ttf");
  157     SFile f(name, fontSearchPath);
  158     if (f.size() > 0 && name.match ("*.hex"))
  159     {
  160       d = new SFontDelegate (f, SFontDelegate::SE_UNIFONT);
  161       CHECK_NEW (d);
  162       delegate = d;
  163       fontCache.put (decorated, d);
  164     }
  165     else if (f.size() > 0 && name.match ("*.bdf"))
  166     {
  167       d = new SFontDelegate (f, SFontDelegate::SE_BDF);
  168       CHECK_NEW (d);
  169       delegate = d;
  170       fontCache.put (decorated, d);
  171     }
  172     else if (f.size() > 0)
  173     {
  174       if (encoding.size()==0 || encoding == name || encoding == SString("unicode"))
  175       {
  176          d = new SFontDelegate (f, SFontDelegate::SE_TTF);
  177       }
  178       else
  179       {
  180          /* xlfd contains encoding */
  181          d = new SFontDelegate (f, SFontDelegate::SE_TTF, encoding);
  182       }
  183       CHECK_NEW (d);
  184       delegate = d;
  185       // It is obvious that we don't use fontCache at this point.
  186       // FIXME: this was commented out till yudit-2.3.beta-14 !!! Why?
  187       fontCache.put (decorated, d);
  188     }
  189     else
  190     {
  191       createSaneXLFD();
  192 //fprintf (stderr, "name=%*.*s xlfd=%*.*s\n", SSARGS(name), SSARGS(xlfd));
  193       if (encoding.size()==0 || encoding == name)
  194       {
  195         d = new SFontDelegate (xlfd, SFontDelegate::SE_NATIVE);
  196       }
  197       else
  198       {
  199         d = new SFontDelegate (xlfd, SFontDelegate::SE_NATIVE, encoding);
  200       }
  201       CHECK_NEW (d);
  202       delegate = d;
  203       fontCache.put (decorated, d);
  204     }
  205   }
  206 }
  207 void
  208 SFontImpl::createSaneXLFD ()
  209 {
  210   SStringVector l;
  211   xlfd.replace("--", "-*-");
  212   l.split (xlfd, "-");
  213   if (l.size() < 14)
  214   {
  215     //fprintf (stderr, "SFontImpl: Need better XLFD %*.*s. Adding some -*-\n", SSARGS(xlfd));
  216     /* find a good insertion point - FIXME this is not very good here */
  217     unsigned int ipoint = 0;
  218     if (l.size() > 2)
  219     {
  220       ipoint = l.size() -1;
  221       while (ipoint > 0 && l[ipoint-1] != "*") ipoint--;
  222     }
  223     else if (xlfd[0] == '-')
  224     {
  225       while (ipoint < l.size()  && l[ipoint] != "*") ipoint++;
  226       if (ipoint >= l.size())
  227       {
  228         ipoint = 0;
  229       }
  230     }
  231     while (l.size() < 14) l.insert(ipoint, "*");
  232     xlfd = "-";
  233     xlfd.append(l.join ("-"));
  234   }
  235 }
  236 
  237 SFontImpl::SFontImpl (const SFontImpl& ff)
  238 {
  239   name = ff.name;
  240   xlfd = ff.xlfd;
  241   matrix = ff.matrix;
  242   encoding = ff.encoding;
  243   SFontDelegate* d = (SFontDelegate*) ff.delegate;
  244   if (d)
  245   {
  246     d->count++;
  247   }
  248   lrFont = ff.lrFont;
  249   rlFont = ff.rlFont;
  250   delegate = d;
  251 }
  252 
  253 void
  254 SFontImpl::setAttributes (const SProperties& properties)
  255 {
  256   if (properties.get("LR"))
  257   {
  258     lrFont = properties["LR"]==SString("true");
  259   }
  260   if (properties.get("RL"))
  261   {
  262     rlFont = properties["RL"]==SString("true");
  263   }
  264 }
  265 
  266 SFontImpl
  267 SFontImpl::operator= (const SFontImpl& ff)
  268 {
  269   if (&ff == this) return *this;
  270   SFontDelegate* d;
  271   if (ff.delegate == delegate)
  272   {
  273     xlfd = ff.xlfd;
  274     matrix = ff.matrix;
  275     name = ff.name;
  276     encoding = ff.encoding;
  277     lrFont = ff.lrFont;
  278     rlFont = ff.rlFont;
  279     return *this;
  280   }
  281 
  282   /* Get this till name exists */
  283   SString decorated (name);
  284   decorated.append ("~");
  285   decorated.append (encoding);
  286 
  287   xlfd = ff.xlfd;
  288   matrix = ff.matrix;
  289   name = ff.name;
  290   encoding = ff.encoding;
  291   lrFont = ff.lrFont;
  292   rlFont = ff.rlFont;
  293 
  294   if (delegate)
  295   {
  296     d = (SFontDelegate*) delegate;
  297     d->count--;
  298     if (d->count==0)
  299     {
  300       if (fontCache.get (decorated))
  301       {
  302          fontCache.remove (decorated);
  303          delete d;
  304       }
  305       else
  306       {
  307          fprintf (stderr, "SFontImpl.cpp: FontCache does not have: %*.*s\n", 
  308             SSARGS(decorated));
  309       }
  310     }
  311   }
  312   d = (SFontDelegate*) ff.delegate;
  313   if (d)
  314   {
  315     d->count++;
  316   }
  317   delegate = d;
  318   return *this;
  319 }
  320 
  321 bool
  322 SFontImpl::isTTF () const
  323 {
  324   if (delegate)
  325   {
  326     return (((SFontDelegate*) delegate)->type==SFontDelegate::SE_TTF);
  327   }
  328   return false;
  329 }
  330 
  331 /**
  332  * \brief Try to make a fuzzy guess if we need to align the diacritics to
  333  *    the left or to the right.
  334  * left aligned marks will be rendered this way:
  335  *    x----basewith----x
  336  *         x-markwidth-x 
  337  * right aligned marks will be rendered this way:
  338  *    x----basewith----x
  339  *    x-markwidth-x 
  340  */
  341 bool
  342 SFontImpl::isLeftAligned (SS_UCS4 c) const
  343 {
  344   if (delegate && ((SFontDelegate*) delegate)->type==SFontDelegate::SE_TTF)
  345   {
  346     return (((SFontDelegate*)delegate)->u.ttf->isLeftAligned (c));
  347   }
  348   /* 
  349    * X11 font non-spacing marks  will be right aligned. 
  350    * Except for RL scripts .
  351    */
  352   /* 
  353    * FIXME: 
  354    * In reality should check if it is a non-spacing mark.
  355    */
  356   if (c>= 0x500 && c < 0x900)
  357   {
  358      return true;
  359   }
  360   return false;
  361 }
  362 
  363 
  364 SFontImpl::~SFontImpl ()
  365 {
  366   if (delegate)
  367   {
  368     SFontDelegate* d = (SFontDelegate*) delegate;
  369     d->count--;
  370     if (isTTF())
  371     if (d->count==0)
  372     {
  373       /* Get this till name exists */
  374       SString decorated (name);
  375       decorated.append ("~");
  376       decorated.append (encoding);
  377       if (fontCache.get (decorated))
  378       {
  379          fontCache.remove (decorated);
  380          delete d;
  381       }
  382       else
  383       {
  384          fprintf (stderr, "SFontImpl.cpp: FontCache does not have: %*.*s\n", 
  385             SSARGS(decorated));
  386       }
  387     }
  388   }
  389 }
  390 
  391 /**
  392  * set the search path for the font
  393  * This path will be used to locate font files on the disk
  394  * Currently it is used for True Type fonts.
  395  * @param l is the list of directories.
  396  */
  397 void
  398 SFontImpl::setPath(const SStringVector& l)
  399 {
  400 //fprintf (stderr, "set path ...\n");
  401   fontSearchPath = l;
  402 }
  403 
  404 /**
  405  * search files for property in order and set the path to the 
  406  * property. Always add YUDIT_DATA/fonts
  407  */
  408 void
  409 SFontImpl::guessPath (const SStringVector& files, const SString& property)
  410 {
  411   
  412   SStringVector outDataPath;
  413 
  414   for (unsigned int i=0; i<files.size(); i++)
  415   {
  416     SProperties p;
  417     loadProperties (files[i], &p);
  418     if (p.get (property))
  419     {
  420       SStringVector v(p[property], ",:;");
  421       for (unsigned int j=0; j<v.size(); j++)
  422       {
  423          outDataPath.append (v[j]);
  424       }
  425     }
  426   }
  427   SString c1 = getHome();
  428   c1.append ("/.yudit/fonts");
  429   SString c2 = getPrefix();
  430   c2.append ("/fonts");
  431   if (outDataPath.size()!=0)
  432   { 
  433     outDataPath.append (c1); 
  434     outDataPath.append (c2); 
  435     fontSearchPath = outDataPath;
  436   }
  437   else
  438   {
  439     outDataPath.append (c1); 
  440     outDataPath.append (c2); 
  441     outDataPath.append (fontSearchPath);
  442     fontSearchPath = outDataPath;
  443   }
  444 //fprintf (stderr, "fontpath is %*.*s\n", SSARGS(fontSearchPath.join(",")));
  445 }
  446 /**
  447  * get the path using the "yudit.default.path"
  448  */
  449 void
  450 SFontImpl::guessPath()
  451 {
  452   SString c1 = getHome();
  453   c1.append ("/.yudit/yudit.properties");
  454   SString c2 = getPrefix();
  455   c2.append ("/config/yudit.properties");
  456   SStringVector v;
  457   v.append (c1);
  458   v.append (c2);
  459   guessPath (v, "yudit.fontpath");
  460 }
  461 
  462 /**
  463  * Scale the font to the given pointsize.
  464  * @param x is the x axis pointsize
  465  * @param y is the y axis pointsize
  466  */
  467 void
  468 SFontImpl::scale (double x, double y)
  469 {
  470   SS_Matrix2D m;
  471   matrix = m;
  472   if (!delegate) return;
  473   SFontDelegate* d = (SFontDelegate*) delegate;;
  474   SStringVector l;
  475   char tmp[64];
  476   switch (d->type)
  477   {
  478   case SFontDelegate::SE_TTF:
  479     if (d->u.ttf->isOK())
  480     {
  481         double scale = d->u.ttf->scale ();
  482         m.scale (x * scale, y * scale);
  483         matrix = m;
  484     }
  485     break;
  486   case SFontDelegate::SE_NATIVE:
  487     /*
  488     * Modify the currentXLFD and load the font.
  489     * it will be our pixel size. nice eh? 
  490     * A reminder on xlfd:
  491     * -foundry-family-weight-slant-*-style-pixel-*-*-*-spacing-avgWidth-registry-encoding
  492     */
  493     if (d->u.native==0) break;
  494     l.split (xlfd, "-");
  495     sprintf (tmp, "%u", (unsigned int) (y + 0.5));
  496     if (l.size() < 14)
  497     {
  498       fprintf (stderr, "BAD XLFD %*.*s\n", SSARGS(xlfd));
  499       break;
  500     }
  501     l.replace (6, tmp);
  502     xlfd = "-";
  503     xlfd.append(l.join ("-"));
  504     break;
  505   case SFontDelegate::SE_UNIFONT:
  506     if (d->u.unifont==0) break;
  507     m.scale (x, y);
  508     matrix = m;
  509     break;
  510   case SFontDelegate::SE_BDF:
  511     if (d->u.bdf==0) break;
  512     m.scale (x, y);
  513     matrix = m;
  514     break;
  515   case SFontDelegate::SE_NONE:
  516     break;
  517   }
  518   
  519 }
  520 
  521 /**
  522  * Try to draw one single glyph.
  523  * @param canvas is the canvas to draw to 
  524  * @param m is the conversion matrix
  525  * @param uch is the array containing ucs4 
  526  * @prama len is the length of the array
  527  * @return true is drawn.
  528  */
  529 bool
  530 SFontImpl::draw (SCanvas* canvas, const SPen& aPen, const SS_Matrix2D& m, 
  531   SS_UCS4 uch, bool isLRContext, bool isSelected, bool baseOK)
  532 {
  533   SPen pen (aPen);
  534   if (!delegate) return 0;
  535 
  536   SFontDelegate* d = (SFontDelegate*) delegate;;
  537   SS_Matrix2D sd = m * matrix;
  538   switch (d->type)
  539   {
  540   case SFontDelegate::SE_TTF:
  541     if (d->u.ttf->isOK())
  542     {
  543         if (!isSelected && d->u.ttf->getIsEmoji()) 
  544         {
  545           pen.setForeground (SColor("black"));
  546           pen.setBackground (SColor("white"));
  547         }
  548         if (!d->u.ttf->width (m, uch, 0)) return 0;
  549         long larr[8];
  550         larr[0] = 'T' ; larr[1] = 'T'; larr[2] = 'F';
  551         larr[3] = (long)d->u.ttf; larr[4] = (long)uch;
  552         SString key((char*) larr, 5 * sizeof (long));
  553 
  554         /* FIXME: you should in fact use an instance counter. */
  555         key.append ((long)(sd.x0*16000.0)); /* scale-x */
  556         key.append ((long)(sd.y1*16000.0)); /* scale-y */
  557         if (!isLRContext) key.append ("R");
  558         SColor fg = pen.getForeground();
  559         key.append ("fg:");
  560         key.append ((char)fg.red);
  561         key.append ((char)fg.green);
  562         key.append ((char)fg.blue);
  563         key.append ((char)fg.alpha);
  564         double offsetX = 0.0;
  565         double offsetY = 0.0;
  566         /* for better positioning of diacritical marks */
  567         d->u.ttf->getBaseOffsets (sd, uch, &offsetX, &offsetY);
  568         // No need to be part of the key 
  569         //key.append ((long)(offsetX*16000.0)); 
  570         //key.append ((long)(offsetY*16000.0)); 
  571         sd.t0  += offsetX;
  572         sd.t1  += offsetY;
  573 //fprintf (stderr, "draw %x baseOK=%d\n", uch, (int)baseOK);
  574         if (!isSelected && d->u.ttf->getIsEmoji() && !baseOK) 
  575         {
  576           double width = 1.0;
  577 #if 0
  578 fprintf (stderr, "ascent: %g descent: %g offsetX: %g, offsetY: %g\n", 
  579     ascent(), descent(), offsetX, offsetY);
  580 #endif
  581           d->u.ttf->width (sd, uch, &width);
  582           canvas->bitfill(pen.getBackground(), 
  583                 (int) (m.t0), (int) (m.t1-ascent()), 
  584                 (int) (width+1.0),
  585                 (int) (ascent()+descent()+1.0));
  586         }
  587         /* reverse coordinates Y, negative m.t1 */
  588         if (!canvas->beginImage (m.t0+offsetX, m.t1+offsetY, key, pen.getBackground()))
  589         {
  590           // TODO: add color fonts.
  591           canvas->newpath();
  592           /* not cached yet */
  593           d->u.ttf->draw (canvas, sd, uch, isLRContext);
  594           canvas->fill (pen);
  595         }
  596         canvas->endImage ();
  597         return true;
  598     }
  599     break;
  600   case SFontDelegate::SE_NATIVE:
  601     if (d->u.native==0) break;
  602     return (d->u.native->draw (xlfd, canvas, pen, sd, uch));
  603   case SFontDelegate::SE_UNIFONT:
  604     if (d->u.unifont)
  605     {
  606         if (!d->u.unifont->width (matrix.y1, uch, 0)) return 0;
  607         d->u.unifont->draw (matrix.y1, canvas, pen.getForeground(), sd, uch,
  608            (m.x0 < 0));
  609         return true;
  610     }
  611     break;
  612   case SFontDelegate::SE_BDF:
  613     if (d->u.bdf)
  614     {
  615         if (!d->u.bdf->width (matrix.y1, uch, 0)) return 0;
  616         d->u.bdf->draw (matrix.y1, canvas, pen.getForeground(), sd, uch, 
  617           (m.x0 < 0));
  618         return true;
  619     }
  620     break;
  621   case SFontDelegate::SE_NONE:
  622     break;
  623   }
  624   return false;
  625 }
  626 
  627 /**
  628  * @param m is the conversion matrix
  629  * @param uch is the array containing ucs4 
  630  * @prama len is the length of the array
  631  * @return ture if it has width.
  632  *  width_ will be set t width if exists.
  633  */
  634  
  635 bool
  636 SFontImpl::width (SS_UCS4 uch, double* width_)
  637 {
  638   if (!delegate) return false;
  639   SFontDelegate* d = (SFontDelegate*) delegate;;
  640   switch (d->type)
  641   {
  642   case SFontDelegate::SE_TTF:
  643     if (d->u.ttf->isOK())
  644     {
  645         return (d->u.ttf->width (matrix, uch, width_));
  646     }
  647     break;
  648   case SFontDelegate::SE_NATIVE:
  649     if (d->u.native==0) break;
  650     return (d->u.native->width (xlfd, uch, width_));
  651   case SFontDelegate::SE_UNIFONT:
  652     if (d->u.unifont)
  653     {
  654         return (d->u.unifont->width (matrix.y1, uch, width_));
  655     }
  656     break;
  657   case SFontDelegate::SE_BDF:
  658     if (d->u.bdf)
  659     {
  660         return (d->u.bdf->width (matrix.y1, uch, width_));
  661     }
  662     break;
  663   case SFontDelegate::SE_NONE:
  664      break;
  665   }
  666   return false;
  667 }
  668 
  669 /**
  670  * set the base character for better glyph positioning
  671  * @param base is the base character relative to which 
  672  * we will position all of out composing marks.
  673  */
  674 void
  675 SFontImpl::setBase(SS_UCS4 base)
  676 {
  677   SFontTTF::setBase (base);
  678 }
  679 
  680 /**
  681  * return the overall width
  682  */
  683 double
  684 SFontImpl::width () const
  685 {
  686   if (!delegate) return 0.0;
  687 
  688   SFontDelegate* d = (SFontDelegate*) delegate;;
  689   switch (d->type)
  690   {
  691   case SFontDelegate::SE_TTF:
  692     if (d->u.ttf->isOK())
  693     {
  694         return (d->u.ttf->width (matrix));
  695     }
  696     break;
  697   case SFontDelegate::SE_NATIVE:
  698     if (d->u.native==0) break;
  699     return d->u.native->width (xlfd);
  700   case SFontDelegate::SE_UNIFONT:
  701     if (d->u.unifont)
  702     {
  703         return (d->u.unifont->width (matrix.y1));
  704     }
  705     break;
  706   case SFontDelegate::SE_BDF:
  707     if (d->u.bdf)
  708     {
  709         return (d->u.bdf->width (matrix.y1));
  710     }
  711     break;
  712   case SFontDelegate::SE_NONE:
  713      break;
  714   }
  715   return 0.0;
  716 }
  717 
  718 /**
  719  * return the overall ascent
  720  */
  721 double
  722 SFontImpl::ascent () const
  723 {
  724   if (!delegate) return 0.0;
  725 
  726   SFontDelegate* d = (SFontDelegate*) delegate;;
  727   switch (d->type)
  728   {
  729   case SFontDelegate::SE_TTF:
  730     if (d->u.ttf->isOK())
  731     {
  732         return (d->u.ttf->ascent (matrix));
  733     }
  734     break;
  735   case SFontDelegate::SE_NATIVE:
  736     if (d->u.native==0) break;
  737     return d->u.native->ascent (xlfd);
  738   case SFontDelegate::SE_UNIFONT:
  739     if (d->u.unifont)
  740     {
  741         return (d->u.unifont->ascent (matrix.y1));
  742     }
  743     break;
  744   case SFontDelegate::SE_BDF:
  745     if (d->u.bdf)
  746     {
  747         return (d->u.bdf->ascent (matrix.y1));
  748     }
  749     break;
  750   case SFontDelegate::SE_NONE:
  751      break;
  752   }
  753   return 0.0;
  754 }
  755 
  756 
  757 /**
  758  * return the overall descent
  759  */
  760 double
  761 SFontImpl::descent () const
  762 {
  763   if (!delegate) return 0.0;
  764 
  765   SFontDelegate* d = (SFontDelegate*) delegate;;
  766   switch (d->type)
  767   {
  768   case SFontDelegate::SE_TTF:
  769     if (d->u.ttf->isOK())
  770     {
  771         return (d->u.ttf->descent (matrix));
  772     }
  773     break;
  774   case SFontDelegate::SE_NATIVE:
  775     if (d->u.native==0) break;
  776     return d->u.native->descent (xlfd);
  777   case SFontDelegate::SE_UNIFONT:
  778     if (d->u.unifont)
  779     {
  780         return (d->u.unifont->descent (matrix.y1));
  781     }
  782     break;
  783   case SFontDelegate::SE_BDF:
  784     if (d->u.bdf)
  785     {
  786         return (d->u.bdf->descent (matrix.y1));
  787     }
  788     break;
  789   case SFontDelegate::SE_NONE:
  790      break;
  791   }
  792   return 0.0;
  793 }
  794 
  795 /**
  796  * return the overall gap
  797  */
  798 double
  799 SFontImpl::gap () const
  800 {
  801   if (!delegate) return 0.0;
  802 
  803   SFontDelegate* d = (SFontDelegate*) delegate;;
  804   switch (d->type)
  805   {
  806   case SFontDelegate::SE_TTF:
  807     if (d->u.ttf->isOK())
  808     {
  809         return (d->u.ttf->gap (matrix));
  810     }
  811     break;
  812   case SFontDelegate::SE_NATIVE:
  813     if (d->u.native==0) break;
  814     return d->u.native->gap (xlfd);
  815   case SFontDelegate::SE_UNIFONT:
  816     if (d->u.unifont)
  817     {
  818         return (d->u.unifont->gap (matrix.y1));
  819     }
  820     break;
  821   case SFontDelegate::SE_BDF:
  822     if (d->u.bdf)
  823     {
  824         return (d->u.bdf->gap (matrix.y1));
  825     }
  826     break;
  827   case SFontDelegate::SE_NONE:
  828      break;
  829   }
  830   return 0.0;
  831 }
  832 
  833 SObject*
  834 SFontImpl::clone () const
  835 {
  836   SFontImpl *ret =  new SFontImpl(*this);
  837   CHECK_NEW (ret);
  838   return ret;
  839 }
  840 
  841 bool
  842 SFontImpl::needSoftMirror (SS_UCS4 uch, bool isLRContext) const
  843 {
  844   // Sort out strong font types.
  845   if (isLR() && !isLRContext) return true;
  846   if (isRL() && isLRContext) return true;
  847   if (isLR() || isRL()) return false;
  848 
  849   if (getPUARovasType (uch) > 0) return !isLRContext;
  850   if (getRovasType (uch) > 0) return isLRContext;
  851   // rest is LR, need mirroring in RL context.
  852   return !isLRContext;
  853 }