1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 #include <QDebug>
8 #include <QDir>
9 #include <QFileInfo>
10
11 #include "ftface.h"
12 #include "scface_ps.h"
13
14
15
ScFace_PostScript(const QString & fam,const QString & sty,const QString & alt,const QString & scname,const QString & psname,const QString & path,int face,const QStringList & features)16 ScFace_PostScript::ScFace_PostScript(const QString& fam, const QString& sty, const QString& alt, const QString& scname, const QString& psname, const QString& path, int face, const QStringList& features) :
17 FtFace(fam,sty,alt,scname,psname,path,face,features)
18 {
19 isFixedPitch = false;
20 typeCode = ScFace::TYPE1;
21 }
22
findFontMetrics(const QString & fontPath) const23 QStringList ScFace_PostScript::findFontMetrics(const QString& fontPath) const
24 {
25 QStringList metricsFiles;
26 QFileInfo fi(fontPath);
27
28 QString fontDir = fi.absolutePath();
29 QString fontFile = fi.completeBaseName();
30
31 metricsFiles += findFontMetrics(fontDir, fontFile);
32
33 //if no metrics found look in afm and pfm subdirs
34 if ( metricsFiles.empty() )
35 {
36 QDir dir;
37 if (dir.exists(fontDir + "/AFMs"))
38 metricsFiles += findFontMetrics(fontDir + "/AFMs", fontFile);
39 if (dir.exists(fontDir + "/afm") && metricsFiles.empty())
40 metricsFiles += findFontMetrics(fontDir + "/afm", fontFile);
41 if (dir.exists(fontDir + "/Pfm") && metricsFiles.empty())
42 metricsFiles += findFontMetrics(fontDir + "/Pfm", fontFile);
43 if (dir.exists(fontDir + "/pfm") && metricsFiles.empty())
44 metricsFiles += findFontMetrics(fontDir + "/pfm", fontFile);
45 }
46 return metricsFiles;
47 }
48
findFontMetrics(const QString & baseDir,const QString & baseName) const49 QStringList ScFace_PostScript::findFontMetrics(const QString& baseDir, const QString& baseName) const
50 {
51 QStringList metricsFiles;
52 QString afnm = baseDir + "/" + baseName + ".";
53 // Look for afm files
54 QString afmName(afnm + "afm");
55 if (QFile::exists(afmName))
56 metricsFiles.append(afmName);
57 else
58 {
59 afmName = afnm + "Afm";
60 if (QFile::exists(afmName))
61 metricsFiles.append(afmName);
62 else
63 {
64 afmName = afnm + "AFM";
65 if (QFile::exists(afmName))
66 metricsFiles.append(afmName);
67 }
68 }
69 // Look for pfm files
70 QString pfmName(afnm + "pfm");
71 if (QFile::exists(pfmName))
72 metricsFiles.append(pfmName);
73 else
74 {
75 pfmName = afnm + "Pfm";
76 if (QFile::exists(pfmName))
77 metricsFiles.append(pfmName);
78 else
79 {
80 pfmName = afnm + "PFM";
81 if (QFile::exists(pfmName))
82 metricsFiles.append(pfmName);
83 }
84 }
85 return metricsFiles;
86 }
87
loadFontMetrics(FT_Face face,const QString & fontPath) const88 bool ScFace_PostScript::loadFontMetrics(FT_Face face, const QString& fontPath) const
89 {
90 QStringList fontMetrics = findFontMetrics(fontPath);
91 if (fontMetrics.empty())
92 {
93 qDebug() << QObject::tr("No metrics found for font %1, ignoring font").arg(fontPath);
94 return false;
95 }
96
97 bool brokenMetric = false;
98 bool metricsFound = false;
99 QString metricsFile;
100 for (int i = 0; i < fontMetrics.size(); ++i)
101 {
102 metricsFile = fontMetrics.at(i);
103 if (FT_Attach_File(face, metricsFile.toLocal8Bit().constData()) == 0)
104 {
105 if (brokenMetric)
106 qDebug() << QObject::tr("Valid metrics were found for font %1, using metrics in file %2").arg(fontFile, metricsFile);
107 metricsFound = true;
108 break;
109 }
110
111 qDebug() << QObject::tr("Font %1 has broken metrics in file %2, ignoring metrics").arg(fontPath, metricsFile);
112 brokenMetric = true;
113 }
114
115 return metricsFound;
116 }
117
load() const118 void ScFace_PostScript::load() const // routine by Franz Schmid - modified by Alastair M. Robinson
119 {
120 FtFace::load();
121 // bool error;
122 FT_Face face = ftFace();
123 if (!face)
124 {
125 const_cast<ScFace_PostScript*>(this)->usable = false;
126 qDebug("%s", QObject::tr("Font %1 is broken (no Face), discarding it").arg(fontFile).toLocal8Bit().constData());
127 return;
128 }
129 if (loadFontMetrics(face, fontFile))
130 {
131 // re-initialize: ScFaceData::load() just clears caches,
132 // FtFace::load() skips FT_New_Face if m_face is already defined.
133 // don't mind checking glyphs again for now (PS files have only 255 glyphs max, anyway)
134 FtFace::load();
135 }
136 }
137
ScFace_PFB(const QString & fam,const QString & sty,const QString & alt,const QString & scname,const QString & psname,const QString & path,int face,const QStringList & features)138 ScFace_PFB::ScFace_PFB(const QString& fam, const QString& sty, const QString& alt, const QString& scname, const QString& psname, const QString& path, int face, const QStringList& features) :
139 ScFace_PostScript(fam, sty, alt, scname, psname, path, face, features)
140 {
141 formatCode = ScFace::PFB;
142 }
143
embedFont(QByteArray & str) const144 bool ScFace_PFB::embedFont(QByteArray& str) const
145 {
146 QByteArray bb;
147 rawData(bb);
148 if ((bb.size() > 2) && (bb[0] == '\x80') && (static_cast<int>(bb[1]) == 1))
149 {
150 int posi,cxxc=0;
151 for (posi = 6; posi < bb.size(); ++posi)
152 {
153 if ((bb[posi] == '\x80') && (posi + 1 < bb.size()) && (static_cast<int>(bb[posi + 1]) == 2))
154 break;
155 str += bb[posi];
156 }
157 int ulen;
158 if (posi + 6 < bb.size())
159 {
160 ulen = bb[posi + 2] & 0xff;
161 ulen |= (bb[posi + 3] << 8) & 0xff00;
162 ulen |= (bb[posi + 4] << 16) & 0xff0000;
163 ulen |= (bb[posi + 5] << 24) & 0xff000000;
164 posi += 6;
165 if (posi + ulen > bb.size())
166 ulen = bb.size() - posi - 1;
167 char linebuf[80];
168 cxxc = 0;
169 for (int j = 0; j < ulen; ++j)
170 {
171 unsigned char u = bb[posi];
172 linebuf[cxxc] = ((u >> 4) & 15) + '0';
173 if (u>0x9f)
174 linebuf[cxxc] += 'a'-':';
175 ++cxxc;
176 u &= 15;
177 linebuf[cxxc] = u + '0';
178 if (u>0x9)
179 linebuf[cxxc] += 'a'-':';
180 ++posi;
181 ++cxxc;
182 if (cxxc > 72)
183 {
184 linebuf[cxxc++] = '\n';
185 linebuf[cxxc++] = 0;
186 str += linebuf;
187 cxxc = 0;
188 }
189 }
190 linebuf[cxxc] = 0;
191 str += linebuf;
192 str += "\n";
193 }
194 posi += 6;
195 for (int j = posi; j < bb.size(); ++j)
196 {
197 if ((bb[j] == '\x80') && (j + 1 < bb.size()) && (static_cast<int>(bb[j + 1]) == 3))
198 break;
199 if (bb[j] == '\r')
200 str += "\n";
201 else
202 str += bb[j];
203 }
204 str += "\n";
205 return true;
206 }
207 qDebug("%s", QObject::tr("Font %1 cannot be read, no embedding").arg(fontFile).toLatin1().constData());
208 return false;
209 }
210
ScFace_PFA(const QString & fam,const QString & sty,const QString & alt,const QString & scname,const QString & psname,const QString & path,int face,const QStringList & features)211 ScFace_PFA::ScFace_PFA(const QString& fam, const QString& sty, const QString& alt, const QString& scname, const QString& psname, const QString& path, int face, const QStringList& features) :
212 ScFace_PostScript(fam, sty, alt, scname, psname, path, face, features)
213 {
214 formatCode = ScFace::PFA;
215 }
216
embedFont(QByteArray & str) const217 bool ScFace_PFA::embedFont(QByteArray& str) const
218 {
219 QByteArray bb;
220 rawData(bb);
221 if (bb.size() > 2 && bb[0] == '%' && bb[1] == '!')
222 {
223 // this is ok since bb will not contain '\0'
224 str.append(bb);
225 return true;
226 }
227 qDebug("%s", QObject::tr("Font %1 cannot be read, no embedding").arg(fontFile).toLatin1().constData());
228 return false;
229 }
230