Rev 7883 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5979 | avox | 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 <qpainter.h> |
||
8 | #include <qcolor.h> |
||
9 | #include <qwmatrix.h> |
||
10 | #include <qpixmap.h> |
||
11 | #include <qstringlist.h> |
||
12 | #include <qmap.h> |
||
13 | #include <qregexp.h> |
||
14 | |||
15 | #include "scribusdoc.h" |
||
16 | #include "scfonts.h" |
||
17 | #include "style.h" |
||
18 | #include "scfontmetrics.h" |
||
19 | #include "scpainter.h" |
||
20 | #include "fpoint.h" |
||
21 | #include "fpointarray.h" |
||
22 | #include "page.h" |
||
23 | #include "util.h" |
||
24 | |||
25 | // this code contains a set of font related functions |
||
26 | // that don't really fit within ScFonts. |
||
27 | |||
28 | static FPoint firstP; |
||
29 | static bool FirstM; |
||
30 | static QMap<FT_ULong, QString> adobeGlyphNames; |
||
31 | static const char* table[] = { |
||
32 | //#include "glyphnames.txt.q" |
||
33 | NULL}; |
||
34 | |||
35 | // private functions |
||
36 | static void readAdobeGlyphNames(); |
||
37 | static QString adobeGlyphName(FT_ULong charcode); |
||
38 | static int traceMoveto( FT_Vector *to, FPointArray *composite ); |
||
39 | static int traceLineto( FT_Vector *to, FPointArray *composite ); |
||
40 | static int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, FPointArray *composite ); |
||
41 | static int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, FPointArray *composite ); |
||
42 | |||
43 | FT_Outline_Funcs OutlineMethods = |
||
44 | { |
||
45 | (FT_Outline_MoveTo_Func) traceMoveto, |
||
46 | (FT_Outline_LineTo_Func) traceLineto, |
||
47 | (FT_Outline_ConicTo_Func) traceQuadraticBezier, |
||
48 | (FT_Outline_CubicTo_Func) traceCubicBezier, |
||
49 | 0, |
||
50 | |||
51 | }; |
||
52 | |||
53 | |||
54 | const double FTSCALE = 64.0; |
||
55 | |||
56 | |||
57 | int setBestEncoding(FT_Face face) |
||
58 | { |
||
59 | FT_ULong charcode; |
||
60 | FT_UInt gindex; |
||
61 | bool foundEncoding = false; |
||
62 | int countUniCode = 0; |
||
63 | int chmapUniCode = -1; |
||
64 | int chmapCustom = -1; |
||
65 | int retVal = 0; |
||
66 | //FT_CharMap defaultEncoding = face->charmap; |
||
67 | // int defaultchmap=face->charmap ? FT_Get_Charmap_Index(face->charmap) : 0; |
||
68 | // Since the above function is only available in FreeType 2.1.10 its replaced by |
||
69 | // the following line, assuming that the default charmap has the index 0 |
||
70 | int defaultchmap = 0; |
||
71 | for(int u = 0; u < face->num_charmaps; u++) |
||
72 | { |
||
73 | if (face->charmaps[u]->encoding == FT_ENCODING_UNICODE ) |
||
74 | { |
||
75 | FT_Set_Charmap(face, face->charmaps[u]); |
||
76 | chmapUniCode = u; |
||
77 | gindex = 0; |
||
78 | charcode = FT_Get_First_Char( face, &gindex ); |
||
79 | while ( gindex != 0 ) |
||
80 | { |
||
81 | countUniCode++; |
||
82 | charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
||
83 | } |
||
84 | } |
||
85 | if (face->charmaps[u]->encoding == FT_ENCODING_ADOBE_CUSTOM) |
||
86 | { |
||
87 | chmapCustom = u; |
||
88 | foundEncoding = true; |
||
89 | retVal = 1; |
||
90 | break; |
||
91 | } |
||
92 | else if (face->charmaps[u]->encoding == FT_ENCODING_MS_SYMBOL) |
||
93 | { |
||
94 | chmapCustom = u; |
||
95 | foundEncoding = true; |
||
96 | retVal = 2; |
||
97 | break; |
||
98 | } |
||
99 | } |
||
100 | int mapToSet=defaultchmap; |
||
101 | if (chmapUniCode>0 && countUniCode >= face->num_glyphs-1) |
||
102 | { |
||
103 | mapToSet=chmapUniCode; |
||
104 | //FT_Set_Charmap(face, face->charmaps[chmapUniCode]); |
||
105 | retVal = 0; |
||
106 | } |
||
107 | else |
||
108 | if (foundEncoding) |
||
109 | { |
||
110 | mapToSet=chmapCustom; |
||
111 | //FT_Set_Charmap(face, face->charmaps[chmapCustom]); |
||
112 | } |
||
113 | else |
||
114 | { |
||
115 | mapToSet=defaultchmap; |
||
116 | //FT_Set_Charmap(face, defaultEncoding); |
||
117 | retVal = 0; |
||
118 | } |
||
119 | |||
120 | //Fixes #2199, missing glyphs from 1.2.1->1.2.2 |
||
121 | //If the currently wanted character map is not already Unicode... |
||
122 | //if (FT_Get_Charmap_Index(face->charmap)!=chmapUniCode) |
||
123 | if (mapToSet!=chmapUniCode) |
||
124 | { |
||
125 | //Change map so we can count the chars in it |
||
126 | FT_Set_Charmap(face, face->charmaps[mapToSet]); |
||
127 | //Count the characters in the current map |
||
128 | gindex = 0; |
||
129 | int countCurrMap=0; |
||
130 | charcode = FT_Get_First_Char( face, &gindex ); |
||
131 | while ( gindex != 0 ) |
||
132 | { |
||
133 | countCurrMap++; |
||
134 | charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
||
135 | } |
||
136 | //If the last Unicode map we found before has more characters, |
||
137 | //then set it to be the current map. |
||
138 | if (countUniCode>countCurrMap) |
||
139 | { |
||
140 | mapToSet=chmapUniCode; |
||
141 | //FT_Set_Charmap(face, face->charmaps[chmapUniCode]); |
||
142 | retVal = 0; |
||
143 | } |
||
144 | } |
||
145 | // if (face->charmap == NULL || mapToSet!=FT_Get_Charmap_Index(face->charmap)) |
||
146 | FT_Set_Charmap(face, face->charmaps[mapToSet]); |
||
147 | return retVal; |
||
148 | } |
||
149 | |||
150 | FPointArray traceGlyph(FT_Face face, FT_UInt glyphIndex, int chs, double *x, double *y, bool *err) |
||
151 | { |
||
152 | bool error = false; |
||
153 | //AV: not threadsave, but tracechar is only used in ReadMetrics() and fontSample() |
||
154 | static FPointArray pts; |
||
155 | FPointArray pts2; |
||
156 | pts.resize(0); |
||
157 | pts2.resize(0); |
||
158 | firstP = FPoint(0,0); |
||
159 | FirstM = true; |
||
160 | error = FT_Set_Char_Size( face, 0, chs*6400, 72, 72 ); |
||
161 | if (error) |
||
162 | { |
||
163 | *err = error; |
||
164 | return pts2; |
||
165 | } |
||
166 | if (glyphIndex == 0) |
||
167 | { |
||
168 | *err = true; |
||
169 | return pts2; |
||
170 | } |
||
171 | error = FT_Load_Glyph( face, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP ); |
||
172 | if (error) |
||
173 | { |
||
174 | *err = error; |
||
175 | return pts2; |
||
176 | } |
||
177 | error = FT_Outline_Decompose(&face->glyph->outline, &OutlineMethods, reinterpret_cast<void*>(&pts)); |
||
178 | if (error) |
||
179 | { |
||
180 | *err = error; |
||
181 | return pts2; |
||
182 | } |
||
183 | *x = face->glyph->metrics.horiBearingX / 6400.0; |
||
184 | *y = face->glyph->metrics.horiBearingY / 6400.0; |
||
185 | QWMatrix ma; |
||
186 | ma.scale(0.01, -0.01); |
||
187 | pts.map(ma); |
||
188 | pts.translate(0, chs); |
||
189 | pts2.putPoints(0, pts.size()-2, pts, 0); |
||
190 | |||
191 | return pts2; |
||
192 | } |
||
193 | |||
194 | |||
195 | FPointArray traceChar(FT_Face face, uint chr, int chs, double *x, double *y, bool *err) |
||
196 | { |
||
197 | bool error = false; |
||
198 | FT_UInt glyphIndex; |
||
199 | error = FT_Set_Char_Size( face, 0, chs*64, 72, 72 ); |
||
200 | if (error) |
||
201 | { |
||
202 | *err = error; |
||
203 | return FPointArray(); |
||
204 | } |
||
205 | glyphIndex = FT_Get_Char_Index(face, chr); |
||
6222 | fschmid | 206 | return traceGlyph(face, glyphIndex, chs, x, y, err); |
5979 | avox | 207 | } |
208 | |||
209 | |||
5989 | jghali | 210 | QPixmap FontSample(const ScFace& fnt, int s, QString ts, QColor back, bool force) |
5979 | avox | 211 | { |
212 | FT_Face face; |
||
213 | FT_Library library; |
||
214 | double x, y, ymax; |
||
215 | bool error; |
||
216 | int pen_x; |
||
217 | FPoint gp; |
||
218 | error = FT_Init_FreeType( &library ); |
||
5989 | jghali | 219 | error = FT_New_Face( library, QFile::encodeName(fnt.fontFilePath()), fnt.faceIndex(), &face ); |
5979 | avox | 220 | int encode = setBestEncoding(face); |
221 | double uniEM = static_cast<double>(face->units_per_EM); |
||
7883 | fschmid | 222 | |
223 | double m_descent = face->descender / uniEM; |
||
224 | double m_height = face->height / uniEM; |
||
225 | if (m_height == 0) |
||
226 | m_height = (face->bbox.yMax - face->bbox.yMin) / uniEM; |
||
227 | |||
228 | int h = qRound(m_height * s) + 1; |
||
229 | double a = m_descent * s + 1; |
||
5979 | avox | 230 | int w = qRound((face->bbox.xMax - face->bbox.xMin) / uniEM) * s * (ts.length()+1); |
231 | if (w < 1) |
||
232 | w = s * (ts.length()+1); |
||
233 | if (h < 1) |
||
234 | h = s; |
||
235 | QPixmap pm(w, h); |
||
236 | pm.fill(); |
||
237 | pen_x = 0; |
||
238 | ymax = 0.0; |
||
239 | ScPainter *p = new ScPainter(&pm, pm.width(), pm.height()); |
||
240 | p->setFillMode(1); |
||
241 | p->setLineWidth(0.0); |
||
242 | p->setBrush(back); |
||
243 | p->drawRect(0.0, 0.0, static_cast<double>(w), static_cast<double>(h)); |
||
244 | p->setBrush(Qt::black); |
||
245 | FPointArray gly; |
||
246 | uint dv; |
||
247 | dv = ts[0].unicode(); |
||
248 | error = false; |
||
249 | gly = traceChar(face, dv, s, &x, &y, &error); |
||
250 | if (((encode != 0) || (error)) && (!force)) |
||
251 | { |
||
252 | error = false; |
||
253 | FT_ULong charcode; |
||
254 | FT_UInt gindex; |
||
255 | gindex = 0; |
||
256 | charcode = FT_Get_First_Char(face, &gindex ); |
||
257 | for (uint n = 0; n < ts.length(); ++n) |
||
258 | { |
||
259 | gly = traceChar(face, charcode, s, &x, &y, &error); |
||
260 | if (error) |
||
261 | break; |
||
262 | if (gly.size() > 3) |
||
263 | { |
||
6222 | fschmid | 264 | gly.translate(static_cast<double>(pen_x) / 6400.0, a); |
5979 | avox | 265 | gp = getMaxClipF(&gly); |
266 | ymax = QMAX(ymax, gp.y()); |
||
267 | p->setupPolygon(&gly); |
||
268 | p->fillPath(); |
||
269 | } |
||
270 | pen_x += face->glyph->advance.x; |
||
271 | charcode = FT_Get_Next_Char(face, charcode, &gindex ); |
||
272 | if (gindex == 0) |
||
273 | break; |
||
274 | } |
||
275 | } |
||
276 | else |
||
277 | { |
||
278 | for (uint n = 0; n < ts.length(); ++n) |
||
279 | { |
||
280 | dv = ts[n].unicode(); |
||
281 | error = false; |
||
282 | gly = traceChar(face, dv, s, &x, &y, &error); |
||
283 | if (gly.size() > 3) |
||
284 | { |
||
6222 | fschmid | 285 | gly.translate(static_cast<double>(pen_x) / 6400.0, a); |
5979 | avox | 286 | gp = getMaxClipF(&gly); |
287 | ymax = QMAX(ymax, gp.y()); |
||
288 | p->setupPolygon(&gly); |
||
289 | p->fillPath(); |
||
290 | } |
||
291 | pen_x += face->glyph->advance.x; |
||
292 | } |
||
293 | } |
||
294 | p->end(); |
||
295 | pm.resize(QMIN(qRound(gp.x()), w), QMIN(qRound(ymax), h)); |
||
296 | delete p; |
||
297 | FT_Done_FreeType( library ); |
||
298 | return pm; |
||
299 | } |
||
300 | |||
301 | /** Same as FontSample() with \n strings support added. |
||
302 | 09/26/2004 petr vanek |
||
303 | |||
304 | QPixmap fontSamples(ScFace * fnt, int s, QString ts, QColor back) |
||
305 | { |
||
306 | QStringList lines = QStringList::split("\n", ts); |
||
307 | QPixmap ret(640, 480); |
||
308 | QPixmap sample; |
||
309 | QPainter *painter = new QPainter(&ret); |
||
310 | int y = 0; |
||
311 | int x = 0; |
||
312 | ret.fill(back); |
||
313 | for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) |
||
314 | { |
||
315 | sample = FontSample(fnt, s, *it, back); |
||
316 | if (!sample.isNull()) |
||
317 | painter->drawPixmap(0, y, sample, 0, 0); |
||
318 | y = y + sample.height(); |
||
319 | if (x < sample.width()) |
||
320 | x = sample.width(); |
||
321 | } // for |
||
322 | delete(painter); |
||
323 | QPixmap final(x, y); |
||
324 | if ((x != 0) && (y != 0)) |
||
325 | { |
||
326 | QPainter *fpainter = new QPainter(&final); |
||
327 | fpainter->drawPixmap(0, 0, ret, 0, 0, x, y); |
||
328 | delete(fpainter); |
||
329 | } |
||
330 | return final; |
||
331 | } |
||
332 | */ |
||
333 | |||
6163 | avox | 334 | bool GlyNames(FT_Face face, QMap<uint, std::pair<QChar, QString> >& GList) |
5979 | avox | 335 | { |
336 | char buf[50]; |
||
337 | FT_ULong charcode; |
||
338 | FT_UInt gindex; |
||
339 | setBestEncoding(face); |
||
340 | gindex = 0; |
||
341 | charcode = FT_Get_First_Char(face, &gindex ); |
||
342 | const bool hasPSNames = FT_HAS_GLYPH_NAMES(face); |
||
343 | if (adobeGlyphNames.empty()) |
||
344 | readAdobeGlyphNames(); |
||
345 | while (gindex != 0) |
||
346 | { |
||
347 | bool notfound = true; |
||
348 | if (hasPSNames) |
||
349 | notfound = FT_Get_Glyph_Name(face, gindex, &buf, 50); |
||
350 | |||
351 | // just in case FT gives empty string or ".notdef" |
||
352 | // no valid glyphname except ".notdef" starts with '.' |
||
353 | if (notfound || buf[0] == '\0' || buf[0] == '.') |
||
6163 | avox | 354 | GList.insert(gindex, std::make_pair(QChar(static_cast<uint>(charcode)),adobeGlyphName(charcode))); |
5979 | avox | 355 | else |
6163 | avox | 356 | GList.insert(gindex, std::make_pair(QChar(static_cast<uint>(charcode)),QString(reinterpret_cast<char*>(buf)))); |
5979 | avox | 357 | |
358 | charcode = FT_Get_Next_Char(face, charcode, &gindex ); |
||
359 | } |
||
360 | return true; |
||
361 | } |
||
6213 | fschmid | 362 | |
5979 | avox | 363 | |
364 | static int traceMoveto( FT_Vector *to, FPointArray *composite ) |
||
365 | { |
||
366 | double tox = ( to->x / FTSCALE ); |
||
367 | double toy = ( to->y / FTSCALE ); |
||
368 | if (!FirstM) |
||
369 | { |
||
370 | composite->addPoint(firstP); |
||
371 | composite->addPoint(firstP); |
||
372 | composite->setMarker(); |
||
373 | } |
||
374 | else |
||
375 | FirstM = false; |
||
376 | composite->addPoint(tox, toy); |
||
377 | composite->addPoint(tox, toy); |
||
378 | firstP.setXY(tox, toy); |
||
379 | return 0; |
||
380 | } |
||
381 | |||
382 | static int traceLineto( FT_Vector *to, FPointArray *composite ) |
||
383 | { |
||
384 | double tox = ( to->x / FTSCALE ); |
||
385 | double toy = ( to->y / FTSCALE ); |
||
386 | if ( !composite->hasLastQuadPoint(tox, toy, tox, toy, tox, toy, tox, toy)) |
||
387 | composite->addQuadPoint(tox, toy, tox, toy, tox, toy, tox, toy); |
||
388 | return 0; |
||
389 | } |
||
390 | |||
391 | static int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, FPointArray *composite ) |
||
392 | { |
||
393 | double x1 = ( control->x / FTSCALE ); |
||
394 | double y1 = ( control->y / FTSCALE ); |
||
395 | double x2 = ( to->x / FTSCALE ); |
||
396 | double y2 = ( to->y / FTSCALE ); |
||
397 | if ( !composite->hasLastQuadPoint(x2, y2, x1, y1, x2, y2, x2, y2)) |
||
398 | composite->addQuadPoint(x2, y2, x1, y1, x2, y2, x2, y2); |
||
399 | return 0; |
||
400 | } |
||
401 | |||
402 | static int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, FPointArray *composite ) |
||
403 | { |
||
404 | double x1 = ( p->x / FTSCALE ); |
||
405 | double y1 = ( p->y / FTSCALE ); |
||
406 | double x2 = ( q->x / FTSCALE ); |
||
407 | double y2 = ( q->y / FTSCALE ); |
||
408 | double x3 = ( to->x / FTSCALE ); |
||
409 | double y3 = ( to->y / FTSCALE ); |
||
410 | if ( !composite->hasLastQuadPoint(x3, y3, x2, y2, x3, y3, x3, y3) ) |
||
411 | { |
||
412 | composite->setPoint(composite->size()-1, FPoint(x1, y1)); |
||
413 | composite->addQuadPoint(x3, y3, x2, y2, x3, y3, x3, y3); |
||
414 | } |
||
415 | return 0; |
||
416 | } |
||
417 | |||
418 | /// init the Adobe Glyph List |
||
419 | void readAdobeGlyphNames() { |
||
420 | adobeGlyphNames.clear(); |
||
421 | QRegExp pattern("(\\w*);([0-9A-Fa-f]{4})"); |
||
422 | for (uint i=0; table[i]; ++i) { |
||
423 | if (pattern.search(table[i]) >= 0) { |
||
424 | FT_ULong unicode = pattern.cap(2).toULong(0, 16); |
||
425 | qDebug("%s", QString("reading glyph name %1 fo unicode %2(%3)").arg(pattern.cap(1)).arg(unicode).arg(pattern.cap(2)).ascii()); |
||
426 | adobeGlyphNames.insert(unicode, pattern.cap(1)); |
||
427 | } |
||
428 | } |
||
429 | } |
||
430 | |||
431 | |||
432 | /// if in AGL, use that name, else use "uni1234" or "u12345" |
||
433 | QString adobeGlyphName(FT_ULong charcode) { |
||
434 | static const char HEX[] = "0123456789ABCDEF"; |
||
435 | QString result; |
||
436 | if (adobeGlyphNames.contains(charcode)) |
||
437 | return adobeGlyphNames[charcode]; |
||
438 | else if (charcode < 0x10000) { |
||
439 | result = QString("uni") + HEX[charcode>>12 & 0xF] |
||
440 | + HEX[charcode>> 8 & 0xF] |
||
441 | + HEX[charcode>> 4 & 0xF] |
||
442 | + HEX[charcode & 0xF]; |
||
443 | } |
||
444 | else { |
||
445 | result = QString("u"); |
||
446 | for (int i= 28; i >= 0; i-=4) { |
||
447 | if (charcode & (0xF << i)) |
||
448 | result += HEX[charcode >> i & 0xF]; |
||
449 | } |
||
450 | } |
||
451 | return result; |
||
452 | } |
||
453 | |||
454 | /* |
||
455 | double Cwidth(ScribusDoc *, ScFace* scFace, QString ch, int Size, QString ch2) |
||
456 | { |
||
457 | double width; |
||
458 | FT_Vector delta; |
||
459 | FT_Face face; |
||
460 | uint c1 = ch.at(0).unicode(); |
||
461 | uint c2 = ch2.at(0).unicode(); |
||
462 | double size10=Size/10.0; |
||
463 | if (scFace->canRender(ch[0])) |
||
464 | { |
||
465 | width = scFace->charWidth(ch[0])*size10; |
||
466 | face = scFace->ftFace(); |
||
467 | /\**** |
||
468 | Ok, this looks like a regression between Freetype 2.1.9 -> 2.1.10. |
||
469 | Ignoring the value of FT_HAS_KERNING for now -- AV |
||
470 | ****\/ |
||
471 | if (true || FT_HAS_KERNING(face) ) |
||
472 | { |
||
473 | uint cl = FT_Get_Char_Index(face, c1); |
||
474 | uint cr = FT_Get_Char_Index(face, c2); |
||
475 | FT_Error error = FT_Get_Kerning(face, cl, cr, FT_KERNING_UNSCALED, &delta); |
||
476 | if (error) { |
||
477 | qDebug(QString("Error %2 when accessing kerning pair for font %1").arg(scFace->scName()).arg(error)); |
||
478 | } |
||
479 | else { |
||
480 | double uniEM = static_cast<double>(face->units_per_EM); |
||
481 | width += delta.x / uniEM * size10; |
||
482 | } |
||
483 | } |
||
484 | else { |
||
485 | qDebug(QString("Font %1 has no kerning pairs (according to Freetype)").arg(scFace->scName())); |
||
486 | } |
||
487 | return width; |
||
488 | } |
||
489 | else |
||
490 | return size10; |
||
491 | } |
||
492 | |||
493 | double RealCWidth(ScribusDoc *, ScFace* scFace, QString ch, int Size) |
||
494 | { |
||
495 | double w, ww; |
||
496 | uint c1 = ch.at(0).unicode(); |
||
497 | FT_Face face; |
||
498 | if (scFace->canRender(ch.at(0))) |
||
499 | { |
||
500 | face = scFace->ftFace(); |
||
501 | uint cl = FT_Get_Char_Index(face, c1); |
||
502 | int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); |
||
503 | if (!error) { |
||
504 | double uniEM = static_cast<double>(face->units_per_EM); |
||
505 | w = (face->glyph->metrics.width + fabs((double)face->glyph->metrics.horiBearingX)) / uniEM * (Size / 10.0); |
||
506 | ww = face->glyph->metrics.horiAdvance / uniEM * (Size / 10.0); |
||
507 | return QMAX(ww, w); |
||
508 | } |
||
509 | else |
||
510 | sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error)); |
||
511 | |||
512 | } |
||
513 | return static_cast<double>(Size / 10.0); |
||
514 | } |
||
515 | |||
516 | double RealCHeight(ScribusDoc *, ScFace* scFace, QString ch, int Size) |
||
517 | { |
||
518 | double w; |
||
519 | uint c1 = ch.at(0).unicode(); |
||
520 | FT_Face face; |
||
521 | if (scFace->canRender(ch.at(0))) |
||
522 | { |
||
523 | face = scFace->ftFace(); |
||
524 | uint cl = FT_Get_Char_Index(face, c1); |
||
525 | int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); |
||
526 | if (!error) { |
||
527 | double uniEM = static_cast<double>(face->units_per_EM); |
||
528 | w = face->glyph->metrics.height / uniEM * (Size / 10.0); |
||
529 | } |
||
530 | else { |
||
531 | sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error)); |
||
532 | w = Size / 10.0; |
||
533 | } |
||
534 | return w; |
||
535 | } |
||
536 | else |
||
537 | return static_cast<double>(Size / 10.0); |
||
538 | } |
||
539 | |||
540 | double RealCAscent(ScribusDoc *, ScFace* scFace, QString ch, int Size) |
||
541 | { |
||
542 | double w; |
||
543 | uint c1 = ch.at(0).unicode(); |
||
544 | FT_Face face; |
||
545 | if (scFace->canRender(ch.at(0))) |
||
546 | { |
||
547 | face = scFace->ftFace(); |
||
548 | uint cl = FT_Get_Char_Index(face, c1); |
||
549 | int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); |
||
550 | if (! error) { |
||
551 | double uniEM = static_cast<double>(face->units_per_EM); |
||
552 | w = face->glyph->metrics.horiBearingY / uniEM * (Size / 10.0); |
||
553 | } |
||
554 | else { |
||
555 | sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error)); |
||
556 | w = Size / 10.0; |
||
557 | } |
||
558 | return w; |
||
559 | } |
||
560 | else |
||
561 | return static_cast<double>(Size / 10.0); |
||
562 | } |
||
563 | |||
564 | double RealFHeight(ScribusDoc *, ScFace* scFace, int Size) |
||
565 | { |
||
566 | FT_Face face = scFace->ftFace(); |
||
567 | double uniEM = static_cast<double>(face->units_per_EM); |
||
568 | return face->height / uniEM * (Size / 10.0); |
||
569 | } |
||
6125 | cbradney | 570 | */ |