Back to index

scribus-ng  1.3.4.dfsg+svn20071115
scfontmetrics.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include <qpainter.h>
00008 #include <qcolor.h>
00009 #include <qwmatrix.h>
00010 #include <qpixmap.h>
00011 #include <qstringlist.h>
00012 #include <qmap.h>
00013 #include <qregexp.h>
00014 
00015 #include "scribusdoc.h"
00016 #include "scfonts.h"
00017 #include "style.h"
00018 #include "scfontmetrics.h"
00019 #include "scpainter.h"
00020 #include "fpoint.h"
00021 #include "fpointarray.h"
00022 #include "page.h"
00023 #include "util.h"
00024 
00025 // this code contains a set of font related functions
00026 // that don't really fit within ScFonts.
00027 
00028 static FPoint firstP;
00029 static bool FirstM;
00030 static QMap<FT_ULong, QString> adobeGlyphNames;
00031 static const char* table[] = {
00032 //#include "glyphnames.txt.q"
00033                                    NULL};
00034 
00035 // private functions
00036 static void readAdobeGlyphNames();
00037 static QString adobeGlyphName(FT_ULong charcode);
00038 static int traceMoveto( FT_Vector *to, FPointArray *composite );
00039 static int traceLineto( FT_Vector *to, FPointArray *composite );
00040 static int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, FPointArray *composite );
00041 static int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, FPointArray *composite );
00042 
00043 FT_Outline_Funcs OutlineMethods =
00044     {
00045         (FT_Outline_MoveTo_Func) traceMoveto,
00046         (FT_Outline_LineTo_Func) traceLineto,
00047         (FT_Outline_ConicTo_Func) traceQuadraticBezier,
00048         (FT_Outline_CubicTo_Func) traceCubicBezier,
00049         0,
00050         0
00051     };
00052 
00053 
00054 const double FTSCALE = 64.0;
00055 
00056 
00057 int setBestEncoding(FT_Face face)
00058 {
00059        FT_ULong  charcode;
00060        FT_UInt   gindex;
00061        bool foundEncoding = false;
00062        int countUniCode = 0;
00063        int chmapUniCode = -1;
00064        int chmapCustom = -1;
00065        int retVal = 0;
00066        //FT_CharMap defaultEncoding = face->charmap;
00067 //     int defaultchmap=face->charmap ? FT_Get_Charmap_Index(face->charmap) : 0;
00068 // Since the above function is only available in FreeType 2.1.10 its replaced by
00069 // the following line, assuming that the default charmap has the index 0
00070        int defaultchmap = 0;
00071        for(int u = 0; u < face->num_charmaps; u++)
00072        {
00073               if (face->charmaps[u]->encoding == FT_ENCODING_UNICODE )
00074               {
00075                      FT_Set_Charmap(face, face->charmaps[u]);
00076                      chmapUniCode = u;
00077                      gindex = 0;
00078                      charcode = FT_Get_First_Char( face, &gindex );
00079                      while ( gindex != 0 )
00080                      {
00081                             countUniCode++;
00082                             charcode = FT_Get_Next_Char( face, charcode, &gindex );
00083                      }
00084               }
00085               if (face->charmaps[u]->encoding == FT_ENCODING_ADOBE_CUSTOM)
00086               {
00087                      chmapCustom = u;
00088                      foundEncoding = true;
00089                      retVal = 1;
00090                      break;
00091               }
00092               else if (face->charmaps[u]->encoding == FT_ENCODING_MS_SYMBOL)
00093               {
00094                      chmapCustom = u;
00095                      foundEncoding = true;
00096                      retVal = 2;
00097                      break;
00098               }
00099        }
00100        int mapToSet=defaultchmap;
00101        if (chmapUniCode>0 && countUniCode >= face->num_glyphs-1)
00102        {
00103               mapToSet=chmapUniCode;
00104               //FT_Set_Charmap(face, face->charmaps[chmapUniCode]);
00105               retVal = 0;
00106        }
00107        else
00108        if (foundEncoding)
00109        {
00110               mapToSet=chmapCustom;
00111               //FT_Set_Charmap(face, face->charmaps[chmapCustom]);
00112        }
00113        else
00114        {
00115               mapToSet=defaultchmap;
00116               //FT_Set_Charmap(face, defaultEncoding);
00117               retVal = 0;
00118        }
00119 
00120        //Fixes #2199, missing glyphs from 1.2.1->1.2.2
00121        //If the currently wanted character map is not already Unicode...
00122        //if (FT_Get_Charmap_Index(face->charmap)!=chmapUniCode)
00123        if (mapToSet!=chmapUniCode)
00124        {
00125               //Change map so we can count the chars in it
00126               FT_Set_Charmap(face, face->charmaps[mapToSet]);
00127               //Count the characters in the current map
00128               gindex = 0;
00129               int countCurrMap=0;
00130               charcode = FT_Get_First_Char( face, &gindex );
00131               while ( gindex != 0 )
00132               {
00133                      countCurrMap++;
00134                      charcode = FT_Get_Next_Char( face, charcode, &gindex );
00135               }
00136               //If the last Unicode map we found before has more characters,
00137               //then set it to be the current map.
00138               if (countUniCode>countCurrMap)
00139               {
00140                      mapToSet=chmapUniCode;
00141                      //FT_Set_Charmap(face, face->charmaps[chmapUniCode]);
00142                      retVal = 0;
00143               }
00144        }
00145 //     if (face->charmap == NULL || mapToSet!=FT_Get_Charmap_Index(face->charmap))
00146               FT_Set_Charmap(face, face->charmaps[mapToSet]);
00147        return retVal;
00148 }
00149 
00150 FPointArray traceGlyph(FT_Face face, FT_UInt glyphIndex, int chs, double *x, double *y, bool *err)
00151 {
00152        bool error = false;
00153        //AV: not threadsave, but tracechar is only used in ReadMetrics() and fontSample()
00154        static FPointArray pts; 
00155        FPointArray pts2;
00156        pts.resize(0);
00157        pts2.resize(0);
00158        firstP = FPoint(0,0);
00159        FirstM = true;
00160        error = FT_Set_Char_Size( face, 0, chs*6400, 72, 72 );
00161        if (error)
00162        {
00163               *err = error;
00164               return pts2;
00165        }
00166        if (glyphIndex == 0)
00167        {
00168               *err = true;
00169               return pts2;
00170        }
00171        error = FT_Load_Glyph( face, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP );
00172        if (error)
00173        {
00174               *err = error;
00175               return pts2;
00176        }
00177        error = FT_Outline_Decompose(&face->glyph->outline, &OutlineMethods, reinterpret_cast<void*>(&pts));
00178        if (error)
00179        {
00180               *err = error;
00181               return pts2;
00182        }
00183        *x = face->glyph->metrics.horiBearingX / 6400.0;
00184        *y = face->glyph->metrics.horiBearingY / 6400.0;
00185        QWMatrix ma;
00186        ma.scale(0.01, -0.01);
00187        pts.map(ma);
00188        pts.translate(0, chs);
00189        pts2.putPoints(0, pts.size()-2, pts, 0);
00190 
00191        return pts2;
00192 }
00193 
00194 
00195 FPointArray traceChar(FT_Face face, uint chr, int chs, double *x, double *y, bool *err)
00196 {
00197        bool error = false;
00198        FT_UInt glyphIndex;
00199        error = FT_Set_Char_Size( face, 0, chs*64, 72, 72 );
00200        if (error)
00201        {
00202               *err = error;
00203               return FPointArray();
00204        }
00205        glyphIndex = FT_Get_Char_Index(face, chr);
00206        return traceGlyph(face, glyphIndex, chs, x, y, err);
00207 }
00208 
00209 
00210 QPixmap FontSample(const ScFace& fnt, int s, QString ts, QColor back, bool force)
00211 {
00212        FT_Face face;
00213        FT_Library library;
00214        double x, y, ymax;
00215        bool error;
00216        int  pen_x;
00217        FPoint gp;
00218        error = FT_Init_FreeType( &library );
00219        error = FT_New_Face( library, QFile::encodeName(fnt.fontFilePath()), fnt.faceIndex(), &face );
00220        int encode = setBestEncoding(face);
00221        double uniEM = static_cast<double>(face->units_per_EM);
00222 
00223        double m_descent = face->descender / uniEM;
00224        double m_height = face->height / uniEM;
00225        if (m_height == 0)
00226               m_height = (face->bbox.yMax - face->bbox.yMin) / uniEM;
00227 
00228        int h = qRound(m_height * s) + 1;
00229        double a = m_descent * s + 1;
00230        int w = qRound((face->bbox.xMax - face->bbox.xMin) / uniEM) * s * (ts.length()+1);
00231        if (w < 1)
00232               w = s * (ts.length()+1);
00233        if (h < 1)
00234               h = s;
00235        QPixmap pm(w, h);
00236        pm.fill();
00237        pen_x = 0;
00238        ymax = 0.0;
00239        ScPainter *p = new ScPainter(&pm, pm.width(), pm.height());
00240        p->setFillMode(1);
00241        p->setLineWidth(0.0);
00242        p->setBrush(back);
00243        p->drawRect(0.0, 0.0, static_cast<double>(w), static_cast<double>(h));
00244        p->setBrush(Qt::black);
00245        FPointArray gly;
00246        uint dv;
00247        dv = ts[0].unicode();
00248        error = false;
00249        gly = traceChar(face, dv, s, &x, &y, &error);
00250        if (((encode != 0) || (error)) && (!force))
00251        {
00252               error = false;
00253               FT_ULong  charcode;
00254               FT_UInt gindex;
00255               gindex = 0;
00256               charcode = FT_Get_First_Char(face, &gindex );
00257               for (uint n = 0; n < ts.length(); ++n)
00258               {
00259                      gly = traceChar(face, charcode, s, &x, &y, &error);
00260                      if (error)
00261                             break;
00262                      if (gly.size() > 3)
00263                      {
00264                             gly.translate(static_cast<double>(pen_x) / 6400.0, a);
00265                             gp = getMaxClipF(&gly);
00266                             ymax = QMAX(ymax, gp.y());
00267                             p->setupPolygon(&gly);
00268                             p->fillPath();
00269                      }
00270                      pen_x += face->glyph->advance.x;
00271                      charcode = FT_Get_Next_Char(face, charcode, &gindex );
00272                      if (gindex == 0)
00273                             break;
00274               }
00275        }
00276        else
00277        {
00278               for (uint n = 0; n < ts.length(); ++n)
00279               {
00280                      dv = ts[n].unicode();
00281                      error = false;
00282                      gly = traceChar(face, dv, s, &x, &y, &error);
00283                      if (gly.size() > 3)
00284                      {
00285                             gly.translate(static_cast<double>(pen_x) / 6400.0, a);
00286                             gp = getMaxClipF(&gly);
00287                             ymax = QMAX(ymax, gp.y());
00288                             p->setupPolygon(&gly);
00289                             p->fillPath();
00290                      }
00291                      pen_x += face->glyph->advance.x;
00292               }
00293        }
00294        p->end();
00295        pm.resize(QMIN(qRound(gp.x()), w), QMIN(qRound(ymax), h));
00296        delete p;
00297        FT_Done_FreeType( library );
00298        return pm;
00299 }
00300 
00334 bool GlyNames(FT_Face face, QMap<uint, std::pair<QChar, QString> >& GList)
00335 {
00336        char buf[50];
00337        FT_ULong  charcode;
00338        FT_UInt gindex;
00339        setBestEncoding(face);
00340        gindex = 0;
00341        charcode = FT_Get_First_Char(face, &gindex );
00342        const bool hasPSNames = FT_HAS_GLYPH_NAMES(face);
00343        if (adobeGlyphNames.empty())
00344               readAdobeGlyphNames();
00345        while (gindex != 0)
00346        {
00347               bool notfound = true;
00348               if (hasPSNames)
00349                      notfound = FT_Get_Glyph_Name(face, gindex, &buf, 50);
00350 
00351               // just in case FT gives empty string or ".notdef"
00352               // no valid glyphname except ".notdef" starts with '.'         
00353               if (notfound || buf[0] == '\0' || buf[0] == '.')
00354                      GList.insert(gindex, std::make_pair(QChar(static_cast<uint>(charcode)),adobeGlyphName(charcode)));
00355               else
00356                      GList.insert(gindex, std::make_pair(QChar(static_cast<uint>(charcode)),QString(reinterpret_cast<char*>(buf))));
00357                      
00358               charcode = FT_Get_Next_Char(face, charcode, &gindex );
00359        }
00360        return true;
00361 }
00362 
00363 
00364 static int traceMoveto( FT_Vector *to, FPointArray *composite )
00365 {
00366        double tox = ( to->x / FTSCALE );
00367        double toy = ( to->y / FTSCALE );
00368        if (!FirstM)
00369        {
00370               composite->addPoint(firstP);
00371               composite->addPoint(firstP);
00372               composite->setMarker();
00373        }
00374        else
00375               FirstM = false;
00376        composite->addPoint(tox, toy);
00377        composite->addPoint(tox, toy);
00378        firstP.setXY(tox, toy);
00379        return 0;
00380 }
00381 
00382 static int traceLineto( FT_Vector *to, FPointArray *composite )
00383 {
00384        double tox = ( to->x / FTSCALE );
00385        double toy = ( to->y / FTSCALE );
00386        if ( !composite->hasLastQuadPoint(tox, toy, tox, toy, tox, toy, tox, toy))
00387               composite->addQuadPoint(tox, toy, tox, toy, tox, toy, tox, toy);
00388        return 0;
00389 }
00390 
00391 static int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, FPointArray *composite )
00392 {
00393        double x1 = ( control->x / FTSCALE );
00394        double y1 = ( control->y / FTSCALE );
00395        double x2 = ( to->x / FTSCALE );
00396        double y2 = ( to->y / FTSCALE );
00397        if ( !composite->hasLastQuadPoint(x2, y2, x1, y1, x2, y2, x2, y2))
00398               composite->addQuadPoint(x2, y2, x1, y1, x2, y2, x2, y2);
00399        return 0;
00400 }
00401 
00402 static int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, FPointArray *composite )
00403 {
00404        double x1 = ( p->x / FTSCALE );
00405        double y1 = ( p->y / FTSCALE );
00406        double x2 = ( q->x / FTSCALE );
00407        double y2 = ( q->y / FTSCALE );
00408        double x3 = ( to->x / FTSCALE );
00409        double y3 = ( to->y / FTSCALE );
00410        if ( !composite->hasLastQuadPoint(x3, y3, x2, y2, x3, y3, x3, y3) )
00411        {
00412               composite->setPoint(composite->size()-1, FPoint(x1, y1));
00413               composite->addQuadPoint(x3, y3, x2, y2, x3, y3, x3, y3);
00414        }
00415        return 0;
00416 }
00417 
00419 void readAdobeGlyphNames() {
00420        adobeGlyphNames.clear();
00421        QRegExp pattern("(\\w*);([0-9A-Fa-f]{4})");
00422        for (uint i=0; table[i]; ++i) {
00423               if (pattern.search(table[i]) >= 0) {
00424                      FT_ULong unicode = pattern.cap(2).toULong(0, 16);
00425                      qDebug("%s", QString("reading glyph name %1 fo unicode %2(%3)").arg(pattern.cap(1)).arg(unicode).arg(pattern.cap(2)).ascii());
00426                      adobeGlyphNames.insert(unicode, pattern.cap(1));
00427               }
00428        }
00429 }
00430 
00431 
00433 QString adobeGlyphName(FT_ULong charcode) {
00434        static const char HEX[] = "0123456789ABCDEF";
00435        QString result;
00436        if (adobeGlyphNames.contains(charcode))
00437               return adobeGlyphNames[charcode];
00438        else if (charcode < 0x10000) {
00439               result = QString("uni") + HEX[charcode>>12 & 0xF] 
00440                                       + HEX[charcode>> 8 & 0xF] 
00441                                       + HEX[charcode>> 4 & 0xF] 
00442                                       + HEX[charcode     & 0xF];
00443        }
00444        else  {
00445               result = QString("u");
00446               for (int i= 28; i >= 0; i-=4) {
00447                      if (charcode & (0xF << i))
00448                             result += HEX[charcode >> i & 0xF];
00449               }
00450        }
00451        return result;
00452 }
00453 
00454 /*
00455 double Cwidth(ScribusDoc *, ScFace* scFace, QString ch, int Size, QString ch2)
00456 {
00457        double width;
00458        FT_Vector  delta;
00459        FT_Face      face;
00460        uint c1 = ch.at(0).unicode();
00461        uint c2 = ch2.at(0).unicode();
00462        double size10=Size/10.0;
00463        if (scFace->canRender(ch[0]))
00464        {
00465               width = scFace->charWidth(ch[0])*size10;
00466               face = scFace->ftFace();
00467               /\****
00468                      Ok, this looks like a regression between Freetype 2.1.9 -> 2.1.10.
00469                      Ignoring the value of FT_HAS_KERNING for now -- AV
00470                ****\/
00471               if (true || FT_HAS_KERNING(face) )
00472               {
00473                      uint cl = FT_Get_Char_Index(face, c1);
00474                      uint cr = FT_Get_Char_Index(face, c2);
00475                      FT_Error error = FT_Get_Kerning(face, cl, cr, FT_KERNING_UNSCALED, &delta);
00476                      if (error) {
00477                             qDebug(QString("Error %2 when accessing kerning pair for font %1").arg(scFace->scName()).arg(error));
00478                      }
00479                      else {
00480                             double uniEM = static_cast<double>(face->units_per_EM);
00481                             width += delta.x / uniEM * size10;
00482                      }
00483               }
00484               else {
00485                      qDebug(QString("Font %1 has no kerning pairs (according to Freetype)").arg(scFace->scName()));
00486               }
00487               return width;
00488        }
00489        else
00490               return size10;
00491 }
00492 
00493 double RealCWidth(ScribusDoc *, ScFace* scFace, QString ch, int Size)
00494 {
00495        double w, ww;
00496        uint c1 = ch.at(0).unicode();
00497        FT_Face      face;
00498        if (scFace->canRender(ch.at(0)))
00499        {
00500               face = scFace->ftFace();
00501               uint cl = FT_Get_Char_Index(face, c1);
00502               int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
00503               if (!error) {
00504                      double uniEM = static_cast<double>(face->units_per_EM);
00505                      w = (face->glyph->metrics.width + fabs((double)face->glyph->metrics.horiBearingX)) / uniEM * (Size / 10.0);
00506                      ww = face->glyph->metrics.horiAdvance / uniEM * (Size / 10.0);
00507                      return QMAX(ww, w);
00508               }
00509               else
00510                      sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error));
00511 
00512        }
00513        return static_cast<double>(Size / 10.0);
00514 }
00515 
00516 double RealCHeight(ScribusDoc *, ScFace* scFace, QString ch, int Size)
00517 {
00518        double w;
00519        uint c1 = ch.at(0).unicode();
00520        FT_Face      face;
00521        if (scFace->canRender(ch.at(0)))
00522        {
00523               face = scFace->ftFace();
00524               uint cl = FT_Get_Char_Index(face, c1);
00525               int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
00526               if (!error) {
00527                      double uniEM = static_cast<double>(face->units_per_EM);
00528                      w = face->glyph->metrics.height / uniEM * (Size / 10.0);
00529               }
00530               else {
00531                      sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error));
00532                      w = Size / 10.0;
00533               }
00534               return w;
00535        }
00536        else
00537               return static_cast<double>(Size / 10.0);
00538 }
00539 
00540 double RealCAscent(ScribusDoc *, ScFace* scFace, QString ch, int Size)
00541 {
00542        double w;
00543        uint c1 = ch.at(0).unicode();
00544        FT_Face      face;
00545        if (scFace->canRender(ch.at(0)))
00546        {
00547               face = scFace->ftFace();
00548               uint cl = FT_Get_Char_Index(face, c1);
00549               int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
00550               if (! error) {
00551                      double uniEM = static_cast<double>(face->units_per_EM);
00552                      w = face->glyph->metrics.horiBearingY / uniEM * (Size / 10.0);
00553               }
00554               else {
00555                      sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error));
00556                      w = Size / 10.0;
00557               }
00558               return w;
00559        }
00560        else
00561               return static_cast<double>(Size / 10.0);
00562 }
00563 
00564 double RealFHeight(ScribusDoc *, ScFace* scFace, int Size)
00565 {
00566        FT_Face face = scFace->ftFace();
00567        double uniEM = static_cast<double>(face->units_per_EM);
00568        return face->height / uniEM * (Size / 10.0);
00569 }
00570 */