You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kcontrol/kfontinst/kfontinst/FontEngine.cpp

377 lines
11 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Class Name : KFI::CFontEngine
// Author : Craig Drummond
// Project : K Font Installer
// Creation Date : 29/04/2001
// Version : $Revision$ $Date$
//
////////////////////////////////////////////////////////////////////////////////
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
////////////////////////////////////////////////////////////////////////////////
// (C) Craig Drummond, 2001, 2002, 2003, 2004
////////////////////////////////////////////////////////////////////////////////
#include "FontEngine.h"
#include "Misc.h"
#include <kglobal.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <tqregexp.h>
#include <tqfile.h>
#include <ft2build.h>
#include FT_SFNT_NAMES_H
#include FT_TRUETYPE_IDS_H
#include FT_TRUETYPE_TABLES_H
#include FT_TYPE1_TABLES_H
namespace KFI
{
bool CFontEngine::openFont(const TQString &file, int face)
{
bool ok=false;
if(file==itsPath && face==itsFaceIndex)
{
ok=NONE!=itsType;
}
else
{
closeFont();
itsWeight=WEIGHT_MEDIUM;
itsItalic=ITALIC_NONE;
itsPath=file;
itsFaceIndex=face;
itsPsName=TQString();
if(!openFontFt(file) && !itsPsName.isEmpty())
itsType=NONE;
}
return NONE!=itsType;
}
void CFontEngine::closeFont()
{
closeFaceFt();
itsPath=TQString::null;
itsFaceIndex=-1;
itsType=NONE;
}
TQString CFontEngine::weightStr(enum EWeight w)
{
switch(w)
{
case WEIGHT_THIN:
return "Thin";
case WEIGHT_ULTRA_LIGHT:
return "UltraLight";
case WEIGHT_EXTRA_LIGHT:
return "ExtraLight";
case WEIGHT_DEMI:
return "Demi";
case WEIGHT_LIGHT:
return "Light";
case WEIGHT_BOOK:
return "Book";
case WEIGHT_MEDIUM:
return "Medium";
case WEIGHT_REGULAR:
return "Regular";
case WEIGHT_SEMI_BOLD:
return "SemiBold";
case WEIGHT_DEMI_BOLD:
return "DemiBold";
case WEIGHT_BOLD:
return "Bold";
case WEIGHT_EXTRA_BOLD:
return "ExtraBold";
case WEIGHT_ULTRA_BOLD:
return "UltraBold";
case WEIGHT_HEAVY:
return "Heavy";
case WEIGHT_BLACK:
return "Black";
case WEIGHT_UNKNOWN:
default:
return "Medium";
}
}
CFontEngine::EWeight CFontEngine::strToWeight(const char *str)
{
if(NULL==str)
return WEIGHT_MEDIUM; // WEIGHT_UNKNOWN;
else if(kasciistricmp(str, "Bold")==0)
return WEIGHT_BOLD;
else if(kasciistricmp(str, "Black")==0)
return WEIGHT_BLACK;
else if(kasciistricmp(str, "ExtraBold")==0)
return WEIGHT_EXTRA_BOLD;
else if(kasciistricmp(str, "UltraBold")==0)
return WEIGHT_ULTRA_BOLD;
else if(kasciistricmp(str, "ExtraLight")==0)
return WEIGHT_EXTRA_LIGHT;
else if(kasciistricmp(str, "UltraLight")==0)
return WEIGHT_ULTRA_LIGHT;
else if(kasciistricmp(str, "Light")==0)
return WEIGHT_LIGHT;
else if(kasciistricmp(str, "Medium")==0 || kasciistricmp(str, "Normal")==0 || kasciistricmp(str, "Roman")==0)
return WEIGHT_MEDIUM;
else if(kasciistricmp(str, "Regular")==0)
return WEIGHT_MEDIUM; // WEIGHT_REGULAR;
else if(kasciistricmp(str, "Demi")==0)
return WEIGHT_DEMI;
else if(kasciistricmp(str, "SemiBold")==0)
return WEIGHT_SEMI_BOLD;
else if(kasciistricmp(str, "DemiBold")==0)
return WEIGHT_DEMI_BOLD;
else if(kasciistricmp(str, "Thin")==0)
return WEIGHT_THIN;
else if(kasciistricmp(str, "Book")==0)
return WEIGHT_BOOK;
else
return WEIGHT_MEDIUM; // WEIGHT_UNKNOWN;
}
static void removeSymbols(TQString &str)
{
str.replace(TQRegExp("[\\-\\[\\]()]"), " ");
int len=str.length();
TQChar space(' ');
for(int c=0; c<len; ++c)
if(str[c].unicode()<0x20 || str[c].unicode()>0x7E)
str[c]=space;
str=str.simplifyWhiteSpace();
str=str.stripWhiteSpace();
}
static bool lookupName(FT_Face face, int nid, int pid, int eid, FT_SfntName *nameReturn)
{
int n = FT_Get_Sfnt_Name_Count(face);
if(n>0)
{
int i;
FT_SfntName name;
for(i=0; i<n; i++)
if(0==FT_Get_Sfnt_Name(face, i, &name) && name.name_id == nid && name.platform_id == pid &&
(eid < 0 || name.encoding_id == eid))
{
switch(name.platform_id)
{
case TT_PLATFORM_APPLE_UNICODE:
case TT_PLATFORM_MACINTOSH:
if(name.language_id != TT_MAC_LANGID_ENGLISH)
continue;
break;
case TT_PLATFORM_MICROSOFT:
if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES &&
name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM)
continue;
break;
default:
continue;
}
if(name.string_len > 0)
{
*nameReturn = name;
return true;
}
}
}
return false;
}
static TQCString getName(FT_Face face, int nid)
{
FT_SfntName name;
TQCString str;
if(lookupName(face, nid, TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) ||
lookupName(face, nid, TT_PLATFORM_APPLE_UNICODE, -1, &name))
for(unsigned int i=0; i < name.string_len / 2; i++)
str+=0 == name.string[2*i] ? name.string[(2*i)+1] : '_';
else if(lookupName(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, &name)) // Pretend that Apple Roman is ISO 8859-1
for(unsigned int i=0; i < name.string_len; i++)
str+=name.string[i];
return str;
}
bool CFontEngine::openFontFt(const TQString &file)
{
enum ETtfWeight
{
TTF_WEIGHT_UNKNOWN = 0,
TTF_WEIGHT_THIN = 100 +50,
TTF_WEIGHT_EXTRALIGHT = 200 +50,
TTF_WEIGHT_LIGHT = 300 +50,
TTF_WEIGHT_NORMAL = 400 +50,
TTF_WEIGHT_MEDIUM = 500 +50,
TTF_WEIGHT_SEMIBOLD = 600 +50,
TTF_WEIGHT_BOLD = 700 +50,
TTF_WEIGHT_EXTRABOLD = 800 +50,
TTF_WEIGHT_BLACK = 900 +50
};
bool status=FT_New_Face(itsFt.library, TQFile::encodeName(file), 0, &itsFt.face) ? false : true;
if(status)
itsFt.open=true;
PS_FontInfoRec t1info;
if(0==FT_Get_PS_Font_Info(itsFt.face, &t1info))
{
itsFamily=t1info.family_name;
itsType=TYPE_1;
}
else
{
itsFamily=getName(itsFt.face, TT_NAME_ID_FONT_FAMILY);
itsType=TRUE_TYPE;
}
if(itsFamily.isEmpty())
itsFamily=FT_Get_Postscript_Name(itsFt.face);
if(itsFamily.isEmpty())
status=false; // Hmm... couldn't find any of the names!
if(status)
{
removeSymbols(itsFamily);
itsPsName=(FT_Get_Postscript_Name(itsFt.face));
if(TYPE_1==itsType)
{
itsWeight=strToWeight(t1info.weight);
itsItalic=t1info.italic_angle <= -4 || t1info.italic_angle >= 4 ? ITALIC_ITALIC : ITALIC_NONE;
}
else // TrueType...
{
TT_Postscript *post=NULL;
TT_OS2 *os2=NULL;
TT_Header *head=NULL;
bool gotItalic=false;
if(NULL==(os2=(TT_OS2 *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_os2)) || 0xFFFF==os2->version)
itsWeight=WEIGHT_UNKNOWN;
else
{
FT_UShort weight=(os2->usWeightClass>0 && os2->usWeightClass<100) ? os2->usWeightClass*100 : os2->usWeightClass;
if(weight<TTF_WEIGHT_THIN)
itsWeight=WEIGHT_THIN;
else if(weight<TTF_WEIGHT_EXTRALIGHT)
itsWeight=WEIGHT_EXTRA_LIGHT;
else if(weight<TTF_WEIGHT_LIGHT)
itsWeight=WEIGHT_LIGHT;
else if(/*weight<TTF_WEIGHT_NORMAL || */ weight<TTF_WEIGHT_MEDIUM)
itsWeight=WEIGHT_MEDIUM;
else if(weight<TTF_WEIGHT_SEMIBOLD)
itsWeight=WEIGHT_SEMI_BOLD;
else if(weight<TTF_WEIGHT_BOLD)
itsWeight=WEIGHT_BOLD;
else if(weight<TTF_WEIGHT_EXTRABOLD)
itsWeight=WEIGHT_EXTRA_BOLD;
else if(weight<TTF_WEIGHT_BLACK)
itsWeight=WEIGHT_BLACK;
else if(os2->fsSelection&(1 << 5))
itsWeight=WEIGHT_BOLD;
else
itsWeight=WEIGHT_UNKNOWN;
itsItalic=os2->fsSelection&(1 << 0) ? ITALIC_ITALIC : ITALIC_NONE;
gotItalic=true;
}
if(WEIGHT_UNKNOWN==itsWeight)
itsWeight=NULL!=(head=(TT_Header *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_head)) && head->Mac_Style & 1
? WEIGHT_BOLD
: WEIGHT_MEDIUM;
if(!gotItalic && (head!=NULL || NULL!=(head=(TT_Header *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_head))))
{
gotItalic=true;
itsItalic=head->Mac_Style & 2 ? ITALIC_ITALIC: ITALIC_NONE;
}
if(!gotItalic && NULL!=(post=(TT_Postscript *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_post)))
{
struct TFixed
{
TFixed(unsigned long v) : upper(v>>16), lower(v&0xFFFF) {}
short upper,
lower;
float value() { return upper+(lower/65536.0); }
};
gotItalic=true;
itsItalic=0.0f==((TFixed)post->italicAngle).value() ? ITALIC_NONE : ITALIC_ITALIC;
}
}
}
if(!status)
closeFaceFt();
return status;
}
void CFontEngine::closeFaceFt()
{
if(itsFt.open)
{
FT_Done_Face(itsFt.face);
itsFt.open=false;
}
}
CFontEngine::TFtData::TFtData()
: open(false)
{
if(FT_Init_FreeType(&library))
{
std::cerr << "ERROR: FreeType2 failed to initialise\n";
exit(0);
}
}
CFontEngine::TFtData::~TFtData()
{
FT_Done_FreeType(library);
}
}