2 * KFontInst - KDE Font Installer
4 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 // This class contains code inspired/copied/nicked from mkfontscale. Specifically
26 // the getName(), lookupName(), and the getFoundry() routines...
28 // mkfontscale's (C) notice is:
30 Copyright (c) 2002 by Juliusz Chroboczek
32 Permission is hereby granted, free of charge, to any person obtaining a copy
33 of this software and associated documentation files (the "Software"), to deal
34 in the Software without restriction, including without limitation the rights
35 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36 copies of the Software, and to permit persons to whom the Software is
37 furnished to do so, subject to the following conditions:
39 The above copyright notice and this permission notice shall be included in
40 all copies or substantial portions of the Software.
42 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51 #include "FontEngine.h"
54 #include <KDE/KGlobal>
61 #include <sys/types.h>
65 #include FT_SFNT_NAMES_H
66 #include FT_TRUETYPE_IDS_H
67 #include FT_TRUETYPE_TABLES_H
68 #include FT_TYPE1_TABLES_H
69 #include <QtCore/QBuffer>
70 #include <QtCore/QTextStream>
75 static unsigned long ftStreamRead(FT_Stream stream
, unsigned long offset
, unsigned char *buffer
, unsigned long count
)
77 QByteArray
*in((QByteArray
*)stream
->descriptor
.pointer
);
79 if((offset
+count
)<=(unsigned long)in
->size())
81 memcpy(buffer
, &(in
->data()[offset
]), count
);
88 static FT_Error
openFtFace(FT_Library library
, QByteArray
&in
, FT_Long index
, FT_Face
*face
)
94 if(NULL
==(stream
=(FT_Stream
)calloc(1, sizeof(*stream
))))
95 return FT_Err_Out_Of_Memory
;
97 stream
->descriptor
.pointer
= &in
;
98 stream
->pathname
.pointer
= NULL
;
99 stream
->size
= in
.size();
102 stream
->read
= ftStreamRead
;
103 args
.flags
= FT_OPEN_STREAM
;
104 args
.stream
= stream
;
106 error
= FT_Open_Face(library
, &args
, index
, face
);
108 if (FT_Err_Ok
!=error
)
111 (*face
)->face_flags
&= ~FT_FACE_FLAG_EXTERNAL_STREAM
;
116 // TTF : 00 01 00 00 00 5
121 // Type1: %!PS-AdobeFont-1. 17
122 // : ?? ?? ?? ?? ?? ?? %!PS-AdobeFont-1. 23
123 // : %!FontType1-1. 14
124 // : ?? ?? ?? ?? ?? ?? %!FontType1-1. 20
127 // AFM : StartFontMetrics 16
128 // BDF : STARTFONT 20 10
130 static const int constHeaderLen
=69;
132 CFontEngine::EType
CFontEngine::getType(const char *fileName
)
134 EType
type(TYPE_UNKNOWN
);
135 int fd
=::open(fileName
, O_RDONLY
);
139 unsigned char header
[constHeaderLen
];
141 if(constHeaderLen
==::read(fd
, header
, constHeaderLen
))
142 type
=getType(fileName
, header
);
149 CFontEngine::EType
CFontEngine::getType(const char *fileName
, Strigi::InputStream
*in
)
153 static const int constHeaderLen
=69;
155 int n
=in
->read(h
, constHeaderLen
, constHeaderLen
);
159 return getType(fileName
, n
==constHeaderLen
? (const unsigned char *)h
: NULL
);
162 CFontEngine::EType
CFontEngine::getType(const char *fileName
, const unsigned char *header
)
166 if( (0x00==header
[0] && 0x01==header
[1] && 0x00==header
[2] && 0x00==header
[3] && 0x00==header
[4]) ||
167 ('F'==header
[0] && 'F'==header
[1] && 'I'==header
[2] && 'L'==header
[3]) ||
168 ('F'==header
[65] && 'F'==header
[66] && 'I'==header
[67] && 'L'==header
[68]))
171 if('t'==header
[0] && 't'==header
[1] && 'c'==header
[2] && 'f'==header
[3])
174 if('O'==header
[0] && 'T'==header
[1] && 'T'==header
[2] && 'O'==header
[3])
177 if(0x01==header
[0] && 'f'==header
[1] && 'c'==header
[2] && 'p'==header
[3])
180 if(0==memcmp(header
, "STARTFONT", 9) && 0x20==header
[9])
183 if(0==memcmp(header
, "%!PS-AdobeFont-1.", 17) ||
184 0==memcmp(&header
[6], "%!PS-AdobeFont-1.", 17) ||
185 0==memcmp(header
, "%!FontType1-1.", 14) ||
186 0==memcmp(&header
[6], "%!FontType1-1.", 14) ||
187 ('L'==header
[0] && 'W'==header
[1] && 'F'==header
[2] && 'N'==header
[3]) ||
188 ('L'==header
[65] && 'W'==header
[66] && 'F'==header
[67] && 'N'==header
[68]))
191 if(0==memcmp(header
, "StartFontMetrics", 16))
195 // Right mime 'magic' failed, try by extension...
196 if(Misc::checkExt(fileName
, "ttf"))
199 if(Misc::checkExt(fileName
, "ttc"))
202 if(Misc::checkExt(fileName
, "otf"))
205 if(Misc::checkExt(fileName
, "pfa") || Misc::checkExt(fileName
, "pfb"))
209 // NOTE: Do not accept .gz extension - strigi will decompress for us.
210 if(Misc::checkExt(fileName
, "pcf"))
213 if(Misc::checkExt(fileName
, "bdf"))
216 if(Misc::checkExt(fileName
, "afm"))
222 QString
& CFontEngine::fixFoundry(QString
&foundry
)
224 // Try to make foundry similar to that of AFMs...
225 if(foundry
==QString::fromLatin1("ibm"))
226 foundry
=QString::fromLatin1("IBM");
227 else if(foundry
==QString::fromLatin1("urw"))
228 foundry
=QString::fromLatin1("URW");
229 else if(foundry
==QString::fromLatin1("itc"))
230 foundry
=QString::fromLatin1("ITC");
231 else if(foundry
==QString::fromLatin1("nec"))
232 foundry
=QString::fromLatin1("NEC");
233 else if(foundry
==QString::fromLatin1("b&h"))
234 foundry
=QString::fromLatin1("B&H");
237 QChar
*ch(foundry
.data());
238 int len(foundry
.length());
246 isSpace
=ch
->isSpace();
254 bool CFontEngine::openFont(EType type
, QByteArray
&in
, const char *fileName
, int face
)
260 itsWeight
=FC_WEIGHT_MEDIUM
;
261 itsWidth
=FC_WIDTH_NORMAL
;
262 itsSpacing
=FC_PROPORTIONAL
;
263 itsItalic
=FC_SLANT_ROMAN
;
264 itsFamily
=itsFoundry
=itsVersion
=QString();
266 if(in
.size()<=0 && fileName
&& TYPE_UNKNOWN
==type
)
267 type
=getType(fileName
); // Read file header to obtain type...
272 ok
=openFontFt(in
, fileName
, face
, TYPE_TYPE1
==type
);
274 #ifndef HAVE_FcFreeTypeQueryFace
291 void CFontEngine::closeFont()
295 FT_Done_Face(itsFt
.face
);
300 static int strToWeight(const QString
&str
)
303 return FC_WEIGHT_MEDIUM
;
304 else if(str
.contains("Bold", Qt::CaseInsensitive
))
305 return FC_WEIGHT_BOLD
;
306 else if(str
.contains("Heavy", Qt::CaseInsensitive
))
307 return FC_WEIGHT_HEAVY
;
308 else if(str
.contains("Black", Qt::CaseInsensitive
))
309 return FC_WEIGHT_BLACK
;
310 else if(str
.contains("ExtraBold", Qt::CaseInsensitive
))
311 return FC_WEIGHT_EXTRABOLD
;
312 else if(str
.contains("UltraBold", Qt::CaseInsensitive
))
313 return FC_WEIGHT_ULTRABOLD
;
314 else if(str
.contains("ExtraLight", Qt::CaseInsensitive
))
315 return FC_WEIGHT_EXTRALIGHT
;
316 else if(str
.contains("UltraLight", Qt::CaseInsensitive
))
317 return FC_WEIGHT_ULTRALIGHT
;
318 else if(str
.contains("Light", Qt::CaseInsensitive
))
319 return FC_WEIGHT_LIGHT
;
320 else if(str
.contains("Medium", Qt::CaseInsensitive
) ||
321 str
.contains("Normal", Qt::CaseInsensitive
) ||
322 str
.contains("Roman", Qt::CaseInsensitive
))
323 return FC_WEIGHT_MEDIUM
;
324 else if(str
.contains("Regular", Qt::CaseInsensitive
))
325 return FC_WEIGHT_REGULAR
;
326 else if(str
.contains("SemiBold", Qt::CaseInsensitive
))
327 return FC_WEIGHT_SEMIBOLD
;
328 else if(str
.contains("DemiBold", Qt::CaseInsensitive
))
329 return FC_WEIGHT_DEMIBOLD
;
330 else if(str
.contains("Thin", Qt::CaseInsensitive
))
331 return FC_WEIGHT_THIN
;
332 else if(str
.contains("Book", Qt::CaseInsensitive
))
333 return FC_WEIGHT_NORMAL
;
334 else if(str
.contains("Demi", Qt::CaseInsensitive
))
335 return FC_WEIGHT_NORMAL
;
337 return FC_WEIGHT_MEDIUM
;
340 static int strToWidth(const QString
&str
)
343 return KFI_FC_WIDTH_NORMAL
;
344 else if(str
.contains("UltraCondensed", Qt::CaseInsensitive
))
345 return KFI_FC_WIDTH_ULTRACONDENSED
;
346 else if(str
.contains("ExtraCondensed", Qt::CaseInsensitive
))
347 return KFI_FC_WIDTH_EXTRACONDENSED
;
348 else if(str
.contains("SemiCondensed", Qt::CaseInsensitive
))
349 return KFI_FC_WIDTH_SEMICONDENSED
;
350 else if(str
.contains("Condensed", Qt::CaseInsensitive
))
351 return KFI_FC_WIDTH_CONDENSED
;
352 else if(str
.contains("SemiExpanded", Qt::CaseInsensitive
))
353 return KFI_FC_WIDTH_SEMIEXPANDED
;
354 else if(str
.contains("UltraExpanded", Qt::CaseInsensitive
))
355 return KFI_FC_WIDTH_ULTRAEXPANDED
;
356 else if(str
.contains("ExtraExpanded", Qt::CaseInsensitive
))
357 return KFI_FC_WIDTH_EXTRAEXPANDED
;
358 else if(str
.contains("Expanded", Qt::CaseInsensitive
))
359 return KFI_FC_WIDTH_EXPANDED
;
361 return KFI_FC_WIDTH_NORMAL
;
364 static int checkItalic(int it
, const QString
&full
)
366 return (FC_SLANT_ITALIC
==it
&& (-1!=full
.indexOf("Oblique") || -1!=full
.indexOf("Slanted")))
371 static const char * getFoundry(const char *notice
)
375 const char *noticeStr
,
379 static const Map map
[]=
383 { "Bitstream", "Bitstream"},
384 { "Monotype", "Monotype"},
385 { "Linotype", "Linotype"},
386 { "LINOTYPE-HELL", "Linotype"},
389 { "International Typeface Corporation", "ITC"},
390 { "Tiro Typeworks", "Tiro"},
391 { "XFree86", "XFree86"},
392 { "Microsoft", "Microsoft"},
395 { "HanYang System", "Hanyang"},
402 for(entry
=map
; NULL
!=entry
->foundry
; entry
++)
403 if(strstr(notice
, entry
->noticeStr
)!=NULL
)
404 return entry
->foundry
;
409 #ifndef HAVE_FcFreeTypeQueryFace
410 static bool lookupName(FT_Face face
, int nid
, int pid
, int eid
, FT_SfntName
*nameReturn
)
412 int n
= FT_Get_Sfnt_Name_Count(face
);
420 if(0==FT_Get_Sfnt_Name(face
, i
, &name
) && name
.name_id
== nid
&& name
.platform_id
== pid
&&
421 (eid
< 0 || name
.encoding_id
== eid
))
423 switch(name
.platform_id
)
425 case TT_PLATFORM_APPLE_UNICODE
:
426 case TT_PLATFORM_MACINTOSH
:
427 if(name
.language_id
!= TT_MAC_LANGID_ENGLISH
)
430 case TT_PLATFORM_MICROSOFT
:
431 if(name
.language_id
!= TT_MS_LANGID_ENGLISH_UNITED_STATES
&&
432 name
.language_id
!= TT_MS_LANGID_ENGLISH_UNITED_KINGDOM
)
439 if(name
.string_len
> 0)
450 static QByteArray
getName(FT_Face face
, int nid
)
455 if(lookupName(face
, nid
, TT_PLATFORM_MICROSOFT
, TT_MS_ID_UNICODE_CS
, &name
) ||
456 lookupName(face
, nid
, TT_PLATFORM_APPLE_UNICODE
, -1, &name
))
457 for(unsigned int i
=0; i
< name
.string_len
/ 2; i
++)
458 str
+=0 == name
.string
[2*i
] ? name
.string
[(2*i
)+1] : '_';
459 else if(lookupName(face
, nid
, TT_PLATFORM_MACINTOSH
, TT_MAC_ID_ROMAN
, &name
)) // Pretend that Apple Roman is ISO 8859-1
460 for(unsigned int i
=0; i
< name
.string_len
; i
++)
466 static const char * getFoundry(const FT_Face face
, TT_OS2
*os2
)
470 const char *vendorId
,
474 static const int constVendLen
=4;
476 // These are taken from ttmkfdir
477 static const Map map
[]=
484 { "ATEC", "Alltype"},
486 { "BITS", "Bitstream"},
488 { "DYNA", "DynaLab"},
493 { "IMPR", "Impress"},
494 { "LARA", "Larabie"},
495 { "LEAF", "Interleaf"},
496 { "LETR", "letraset"},
497 { "LINO", "Linotype"},
498 { "MACR", "Macromedia"},
499 { "MONO", "Monotype"},
500 { "MS", "Microsoft"},
503 { "PARA", "ParaType"},
511 static char vendor
[constVendLen
+1];
515 if(NULL
!=os2
&& 0xFFFF!=os2
->version
)
518 char vend
[constVendLen
+1];
520 strncpy(vendor
, (const char *)(os2
->achVendID
), constVendLen
);
521 vendor
[constVendLen
]='\0';
523 for(int i
=0; i
<constVendLen
; ++i
)
524 vend
[i
]=toupper(vendor
[i
]);
526 for(entry
=map
; NULL
!=entry
->vendorId
; entry
++)
528 unsigned int len
=strlen(entry
->vendorId
);
530 if(0==memcmp(entry
->vendorId
, vend
, len
))
534 for(int i
=len
; i
<constVendLen
&& ok
; i
++)
535 if(vend
[i
]!=' ' && entry
->vendorId
[i
]!='\0')
539 return entry
->foundry
;
544 const char *foundry
=NULL
;
547 foundry
=getFoundry(getName(face
, TT_NAME_ID_TRADEMARK
));
550 foundry
=getFoundry(getName(face
, TT_NAME_ID_MANUFACTURER
));
552 if(!foundry
&& vendor
[0] && !isspace(vendor
[0]) && '-'!=vendor
[0]) // Some fonts have a totally blank vendor field
556 // Remove any dashes...
557 for(int i
=constVendLen
-1; i
>0; i
--)
561 // Strip any trailing whitepace
562 for(i
=constVendLen
-1; i
>0; i
--)
563 if(isspace(vendor
[i
]))
575 bool CFontEngine::openFontFt(QByteArray
&in
, const char *fileName
, int face
, bool type1
)
577 bool status
=in
.size()<=0
578 ? FT_New_Face(itsFt
.library
, fileName
, face
, &itsFt
.face
) ? false : true
579 : openFtFace(itsFt
.library
, in
, face
, &itsFt
.face
) ? false : true;
586 PS_FontInfoRec t1info
;
589 FT_Get_PS_Font_Info(itsFt
.face
, &t1info
);
591 #ifdef HAVE_FcFreeTypeQueryFace
592 FcPattern
*pat
=FcFreeTypeQueryFace(itsFt
.face
, (FcChar8
*) fileName
, face
, NULL
);
594 itsWeight
=FC_WEIGHT_REGULAR
;
595 itsWidth
=KFI_FC_WIDTH_NORMAL
;
596 itsSpacing
=FC_PROPORTIONAL
;
600 itsFamily
=FC::getFcString(pat
, FC_FAMILY
, face
);
601 FcPatternGetInteger(pat
, FC_WEIGHT
, face
, &itsWeight
);
602 #ifndef KFI_FC_NO_WIDTHS
603 FcPatternGetInteger(pat
, FC_WIDTH
, face
, &itsWidth
);
605 FcPatternGetInteger(pat
, FC_SLANT
, face
, &itsItalic
);
606 FcPatternGetInteger(pat
, FC_SPACING
, face
, &itsSpacing
);
607 itsFoundry
=FC::getFcString(pat
, FC_FOUNDRY
, face
);
610 itsVersion
=t1info
.version
;
615 FcPatternGetInteger(pat
, FC_FONTVERSION
, face
, &version
);
617 itsVersion
.setNum(decodeFixed(version
));
620 FcPatternDestroy(pat
);
621 fixFoundry(itsFoundry
);
630 TTF_WIDTH_ULTRA_CONDENSED
= 1,
631 TTF_WIDTH_EXTRA_CONDENSED
= 2,
632 TTF_WIDTH_CONDENSED
= 3,
633 TTF_WIDTH_SEMI_CONDENSED
= 4,
634 TTF_WIDTH_NORMAL
= 5,
635 TTF_WIDTH_SEMI_EXPANDED
= 6,
636 TTF_WIDTH_EXPANDED
= 7,
637 TTF_WIDTH_EXTRA_EXPANDED
= 8,
638 TTF_WIDTH_ULTRA_EXPANDED
= 9
645 fullName
=t1info
.full_name
;
646 itsFamily
=t1info
.family_name
;
650 fullName
=getName(itsFt
.face
, TT_NAME_ID_FULL_NAME
);
651 itsFamily
=getName(itsFt
.face
, TT_NAME_ID_FONT_FAMILY
);
654 if(itsFamily
.isEmpty())
655 if(fullName
.isEmpty())
656 itsFamily
=fullName
=FT_Get_Postscript_Name(itsFt
.face
);
660 if(fullName
.isEmpty())
663 if(fullName
.isEmpty())
664 status
=false; // Hmm... couldn't find any of the names!
670 itsWeight
=strToWeight(t1info
.weight
);
671 itsItalic
=t1info
.italic_angle
<= -4 || t1info
.italic_angle
>= 4 ? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
;
672 itsWidth
=strToWidth(fullName
);
673 itsItalic
=checkItalic(itsItalic
, fullName
);
674 itsSpacing
=t1info
.is_fixed_pitch
? FC_MONO
: FC_PROPORTIONAL
;
675 itsFoundry
=KFI::getFoundry(t1info
.notice
);
676 itsVersion
=t1info
.version
;
680 #define WEIGHT_UNKNOWN 0xFFFF
681 #define WIDTH_UNKNOWN 0xFFFF
683 TT_Postscript
*post
=(TT_Postscript
*)FT_Get_Sfnt_Table(itsFt
.face
, ft_sfnt_post
);
684 TT_OS2
*os2
=(TT_OS2
*)FT_Get_Sfnt_Table(itsFt
.face
, ft_sfnt_os2
);
685 TT_Header
*head
=(TT_Header
*)FT_Get_Sfnt_Table(itsFt
.face
, ft_sfnt_head
);
686 bool gotItalic
=false;
688 itsWidth
=WIDTH_UNKNOWN
;
689 itsWeight
=WEIGHT_UNKNOWN
;
691 if(NULL
!=os2
&& 0xFFFF!=os2
->version
)
693 if (os2
->usWeightClass
== 0)
695 else if (os2
->usWeightClass
< 150)
696 itsWeight
=FC_WEIGHT_THIN
;
697 else if (os2
->usWeightClass
< 250)
698 itsWeight
=FC_WEIGHT_EXTRALIGHT
;
699 else if (os2
->usWeightClass
< 350)
700 itsWeight
=FC_WEIGHT_LIGHT
;
701 else if (os2
->usWeightClass
< 450)
702 itsWeight
=FC_WEIGHT_REGULAR
;
703 else if (os2
->usWeightClass
< 550)
704 itsWeight
=FC_WEIGHT_MEDIUM
;
705 else if (os2
->usWeightClass
< 650)
706 itsWeight
=FC_WEIGHT_SEMIBOLD
;
707 else if (os2
->usWeightClass
< 750)
708 itsWeight
=FC_WEIGHT_BOLD
;
709 else if (os2
->usWeightClass
< 850)
710 itsWeight
=FC_WEIGHT_EXTRABOLD
;
711 else if (os2
->usWeightClass
< 950)
712 itsWeight
=FC_WEIGHT_BLACK
;
714 switch(os2
->usWidthClass
)
716 case TTF_WIDTH_ULTRA_CONDENSED
:
717 itsWidth
=FC_WIDTH_ULTRACONDENSED
;
719 case TTF_WIDTH_EXTRA_CONDENSED
:
720 itsWidth
=FC_WIDTH_EXTRACONDENSED
;
722 case TTF_WIDTH_CONDENSED
:
723 itsWidth
=FC_WIDTH_CONDENSED
;
725 case TTF_WIDTH_SEMI_CONDENSED
:
726 itsWidth
=FC_WIDTH_SEMICONDENSED
;
728 case TTF_WIDTH_NORMAL
:
729 itsWidth
=FC_WIDTH_NORMAL
;
731 case TTF_WIDTH_SEMI_EXPANDED
:
732 itsWidth
=FC_WIDTH_SEMIEXPANDED
;
734 case TTF_WIDTH_EXPANDED
:
735 itsWidth
=FC_WIDTH_EXPANDED
;
737 case TTF_WIDTH_EXTRA_EXPANDED
:
738 itsWidth
=FC_WIDTH_EXTRAEXPANDED
;
740 case TTF_WIDTH_ULTRA_EXPANDED
:
741 itsWidth
=FC_WIDTH_ULTRAEXPANDED
;
745 itsItalic
=os2
->fsSelection
&(1 << 0) ? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
;
749 if(WEIGHT_UNKNOWN
==itsWeight
)
750 itsWeight
=itsFt
.face
->style_flags
&FT_STYLE_FLAG_BOLD
754 if(WIDTH_UNKNOWN
==itsWidth
)
755 itsWidth
=FC_WIDTH_NORMAL
;
757 if(!gotItalic
&& head
!=NULL
)
760 itsItalic
=head
->Mac_Style
& 2 ? FC_SLANT_ITALIC
: FC_SLANT_ROMAN
;
765 double version
=decodeFixed(head
->Font_Revision
);
768 itsVersion
.setNum(version
);
771 if(!gotItalic
&& NULL
!=post
)
774 itsItalic
=0.0f
==decodeFixed(post
->italicAngle
) ? FC_SLANT_ROMAN
: FC_SLANT_ITALIC
;
777 itsItalic
=checkItalic(itsItalic
, fullName
);
779 if(NULL
!=post
&& post
->isFixedPitch
)
781 TT_HoriHeader
*hhea
=NULL
;
783 if(NULL
!=(hhea
=(TT_HoriHeader
*)FT_Get_Sfnt_Table(itsFt
.face
, ft_sfnt_hhea
)) &&
784 hhea
->min_Left_Side_Bearing
>= 0 && hhea
->xMax_Extent
<= hhea
->advance_Width_Max
)
785 itsSpacing
=FC_CHARCELL
;
790 itsSpacing
=FC_PROPORTIONAL
;
792 itsFoundry
=KFI::getFoundry(itsFt
.face
, os2
);
803 bool CFontEngine::openFontAfm(QByteArray
&in
)
805 bool inMetrics
=false;
807 QTextStream
ds(&in
, QIODevice::ReadOnly
);
811 QString
line(ds
.readLine());
812 line
=line
.simplified();
816 if(0==line
.indexOf("FullName "))
819 itsWidth
=strToWidth(full
);
821 else if(0==line
.indexOf("FamilyName "))
822 itsFamily
=line
.mid(11);
823 else if(0==line
.indexOf("Weight "))
824 itsWeight
=strToWeight(line
.mid(7));
825 else if(0==line
.indexOf("ItalicAngle "))
826 itsItalic
=0.0f
==line
.mid(12).toFloat() ? FC_SLANT_ROMAN
: FC_SLANT_ITALIC
;
827 else if(0==line
.indexOf("IsFixedPitch "))
828 itsSpacing
= ( line
.mid(13).contains("false", Qt::CaseInsensitive
)
829 ? FC_PROPORTIONAL
: FC_MONO
);
830 else if(0==line
.indexOf("Notice "))
831 itsFoundry
=KFI::getFoundry(line
.mid(7).toLatin1());
832 else if(0==line
.indexOf("Version "))
833 itsVersion
=line
.mid(8);
834 else if(0==line
.indexOf("StartCharMetrics"))
838 if(0==line
.indexOf("StartFontMetrics"))
842 if(itsFamily
.isEmpty() && !full
.isEmpty())
845 checkItalic(itsItalic
, full
);
847 return !full
.isEmpty() && !itsFamily
.isEmpty();
850 #ifndef HAVE_FcFreeTypeQueryFace
851 static int charToItalic(char c
)
857 return FC_SLANT_ITALIC
;
860 return FC_SLANT_OBLIQUE
;
864 return FC_SLANT_ROMAN
;
868 static int charToSpacing(char c
)
881 return FC_PROPORTIONAL
;
885 void CFontEngine::parseXlfdBmp(const QString
&xlfd
)
910 // -foundry-family-weight-slant-width-?-pixelSize-pointSize-resX-resY-spacing-avWidth-csReg-csEnc
911 for(entry
=XLFD_FOUNDRY
; -1!=(pos
=xlfd
.indexOf('-', pos
+1)) && entry
<XLFD_END
; ++entry
)
918 itsFoundry
=xlfd
.mid(oldPos
, pos
-oldPos
);
921 itsFamily
=xlfd
.mid(oldPos
, pos
-oldPos
);
924 itsWeight
=strToWeight(xlfd
.mid(oldPos
, pos
-oldPos
).toLocal8Bit());
928 itsItalic
=charToItalic(xlfd
[pos
-1].toLatin1());
931 itsWidth
=strToWidth(xlfd
.mid(oldPos
, pos
-oldPos
));
934 case XLFD_PIXEL_SIZE
:
935 case XLFD_POINT_SIZE
:
941 itsSpacing
=charToSpacing(xlfd
[pos
-1].toLatin1());
952 bool CFontEngine::openFontBdf(QByteArray
&in
)
954 QTextStream
ds(&in
, QIODevice::ReadOnly
);
956 ds
.readLine(); // Skip 1st line.
959 QString
line(ds
.readLine());
961 if(0==line
.indexOf("FONT ", Qt::CaseInsensitive
))
963 parseXlfdBmp(line
.mid(5));
971 static unsigned int readLsb32(QBuffer
&in
)
973 unsigned char num
[4];
975 return 4==in
.read((char *)num
, 4)
976 ? (num
[0])+(num
[1]<<8)+(num
[2]<<16)+(num
[3]<<24)
980 static unsigned int read32(QBuffer
&in
, bool msb
)
984 unsigned char num
[4];
986 return 4==in
.read((char *)num
, 4)
987 ? (num
[0]<<24)+(num
[1]<<16)+(num
[2]<<8)+(num
[3])
991 return readLsb32(in
);
994 static const unsigned int constBitmapMaxProps
=1024;
996 bool CFontEngine::openFontPcf(QByteArray
&in
)
998 bool foundXlfd
=false;
999 const unsigned int contPcfVersion
=(('p'<<24)|('c'<<16)|('f'<<8)|1);
1003 buf
.open(QIODevice::ReadOnly
);
1005 if(contPcfVersion
==readLsb32(buf
))
1007 const unsigned int constPropertiesType
=1;
1009 unsigned int numTables
=readLsb32(buf
),
1016 for(table
=0; table
<numTables
&& !buf
.atEnd() && !foundXlfd
; ++table
)
1018 type
=readLsb32(buf
);
1019 format
=readLsb32(buf
);
1020 size
=readLsb32(buf
);
1021 offset
=readLsb32(buf
);
1022 if(constPropertiesType
==type
)
1024 if(buf
.seek(offset
))
1026 const unsigned int constFormatMask
=0xffffff00;
1028 format
=readLsb32(buf
);
1029 if(0==(format
&constFormatMask
))
1031 const unsigned int constByteMask
=0x4;
1033 bool msb
=format
&constByteMask
;
1034 unsigned int numProps
=read32(buf
, msb
);
1036 if(numProps
>0 && numProps
<constBitmapMaxProps
)
1038 unsigned int strSize
,
1046 } *props
=new struct TProp
[numProps
];
1051 unsigned short prop
;
1053 for(prop
=0; prop
<numProps
; ++prop
)
1055 props
[prop
].name
=read32(buf
, msb
);
1057 props
[prop
].isString
=tmp
? true : false;
1058 props
[prop
].value
=read32(buf
, msb
);
1061 skip
=4-((numProps
*9)%4);
1063 buf
.seek(buf
.pos()+skip
);
1065 strSize
=read32(buf
, msb
);
1069 QByteArray str
=buf
.read(strSize
);
1071 if(str
.size()==(int)strSize
)
1073 // Finally we have the data............
1074 const int constMaxStrLen
=1024;
1076 char tmp
[constMaxStrLen
];
1078 for(prop
=0; prop
<numProps
&& !foundXlfd
; ++prop
)
1079 if(kasciistricmp(&(str
.data()[props
[prop
].name
]), "FONT")==0)
1081 if(props
[prop
].isString
&& strlen(&(str
.data()[props
[prop
].value
])))
1084 strncpy(tmp
, &(str
.data()[props
[prop
].value
]), constMaxStrLen
);
1085 tmp
[constMaxStrLen
-1]='\0';
1097 break; // Forget the other tables...
1106 CFontEngine::TFtData::TFtData()
1109 if(FT_Init_FreeType(&library
))
1111 std::cerr
<< "ERROR: FreeType2 failed to initialise\n";
1116 CFontEngine::TFtData::~TFtData()
1118 FT_Done_FreeType(library
);