Subversion Repositories Scribus

Rev

Rev 5093 | Rev 5929 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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