Subversion Repositories Scribus

Rev

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

Rev Author Line No. Line
15249 jghali 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
*/
5979 avox 7
 
8
#include "scribusapi.h"
9
#include "fonts/scface.h"
6144 avox 10
#include "text/storytext.h"
5979 avox 11
 
7153 jghali 12
ScFace::ScFaceData::ScFaceData() :
7650 jghali 13
        refs(0),
7153 jghali 14
        usage(0),
15
        scName(""),
16
        fontFile("(None)"),
17
        faceIndex(-1),
18
        psName(""),
19
        family(""),
20
        style(""),
21
        variant(""),
22
        forDocument(""),
23
        status(ScFace::NULLFACE),
24
        typeCode(ScFace::UNKNOWN_TYPE),
25
        formatCode(ScFace::UNKNOWN_FORMAT),
26
        usable(false),
27
        embedPs(false),
28
        subset(false),
29
        isStroked(false),
30
        isFixedPitch(false),
31
        hasNames(false),
32
        maxGlyph(0),
33
        cachedStatus(ScFace::UNKNOWN)
34
{
35
}
5979 avox 36
 
13162 malex 37
qreal ScFace::ScFaceData::glyphKerning(uint /*gl1*/, uint /*gl2*/, qreal /*sz*/) const
5979 avox 38
{
39
        return 0.0;
40
}
41
 
42
 
9042 avox 43
bool ScFace::ScFaceData::glyphNames(QMap<uint, std::pair<QChar, QString> >& /*gList*/) const
5979 avox 44
{
45
        return false;
46
}
47
 
48
 
13162 malex 49
QMap<QString,QString> ScFace::ScFaceData::fontDictionary(qreal /*sz*/) const
5979 avox 50
{
51
        return QMap<QString, QString>();
52
}
53
 
6302 avox 54
 
13162 malex 55
GlyphMetrics ScFace::ScFaceData::glyphBBox(uint gl, qreal sz) const
5979 avox 56
{
57
        GlyphMetrics res;
9042 avox 58
        if (gl == 0 || gl >= CONTROL_GLYPHS)
59
        {       res.width   = glyphWidth(gl, sz);
15011 jghali 60
                res.ascent  = (gl == 0? ascent(sz) : 0);
9042 avox 61
                res.descent = 0;
62
                return res;
63
        }
64
        else if (! m_glyphWidth.contains(gl)) {
65
                loadGlyph(gl);
66
        }                      
67
        const struct GlyphData & data(m_glyphOutline[gl]);
68
        res.width = data.bbox_width * sz;
69
        res.ascent = data.bbox_ascent * sz;
70
        res.descent = data.bbox_descent * sz;  
5979 avox 71
        return res;
72
}
73
 
74
 
13162 malex 75
qreal ScFace::ScFaceData::glyphWidth(uint gl, qreal size) const
5979 avox 76
{
6978 avox 77
        if (gl >= CONTROL_GLYPHS)
6935 avox 78
                return 0.0;
7503 avox 79
        else if (gl == 0)
80
                return size;
6935 avox 81
        else if (! m_glyphWidth.contains(gl)) {
5979 avox 82
                loadGlyph(gl);
83
        }              
84
        return m_glyphWidth[gl] * size;
85
}
86
 
87
 
13162 malex 88
FPointArray ScFace::ScFaceData::glyphOutline(uint gl, qreal sz) const
5979 avox 89
{
6978 avox 90
        if (gl >= CONTROL_GLYPHS)
6935 avox 91
                return FPointArray();
7503 avox 92
        else if (gl == 0) {
8074 avox 93
                sz *= 10;
7503 avox 94
                FPointArray sq;
95
                sq.addQuadPoint(0,0,0,0,sz,0,sz,0);
96
                sq.addQuadPoint(sz,0,sz,0,sz,sz,sz,sz);
97
                sq.addQuadPoint(sz,sz,sz,sz,0,sz,0,sz);
98
                sq.addQuadPoint(0,sz,0,sz,0,0,0,0);
99
                return sq;
100
        }
6935 avox 101
        else if (! m_glyphWidth.contains(gl)) {
5979 avox 102
                loadGlyph(gl);
103
        }                      
104
        FPointArray res = m_glyphOutline[gl].Outlines.copy();
105
        if (sz != 1.0)
106
                res.scale(sz, sz);
107
        return res;
108
}
109
 
110
 
13162 malex 111
FPoint ScFace::ScFaceData::glyphOrigin(uint gl, qreal sz) const
5979 avox 112
{
7503 avox 113
        if (gl == 0 || gl >= CONTROL_GLYPHS)
6935 avox 114
                return FPoint(0,0);
115
        else if (! m_glyphWidth.contains(gl)) {
5979 avox 116
                loadGlyph(gl);
117
        }                      
118
        const struct GlyphData & res(m_glyphOutline[gl]);
119
        return FPoint(res.x, res.y) * sz;
120
}
121
 
122
 
123
/*****
124
   ScFace lifecycle:  unchecked -> loaded -> glyphs checked
125
                               |         \-> broken glyphs
126
                                                           \-> broken
127
   usable() == ! broken
128
   embeddable() == glyphs_checked
129
 
130
   canRender(unicode) -> CharMap cache? -> loadChar/Glyph -> !broken
131
   Glyphs:  width    status
132
            -1000    unkown
133
            -2000    broken
134
            >= 0     ok, outline valid
135
   CharMap:  unicode -> glyph index
136
             uint[256][256]
137
   unicode ignores: < 32, ...
138
   unicode emulate: spaces, hyphen, ligatures?, diacritics?
139
 *****/
140
 
6733 avox 141
ScFace::ScFace() :  replacedName(), replacedInDoc()
5979 avox 142
{
143
        m = new ScFaceData();
144
        m->refs = 1;
145
        m->usage = 0;
146
}
147
 
148
 
6733 avox 149
ScFace::ScFace(ScFaceData* data) : replacedName(), replacedInDoc()
5979 avox 150
{
151
        m = data;
7650 jghali 152
        ++(m->refs);
5979 avox 153
        m->cachedStatus = ScFace::UNKNOWN;
154
}
155
 
6733 avox 156
ScFace::ScFace(const ScFace& other) : replacedName(other.replacedName), replacedInDoc(other.replacedInDoc)
5979 avox 157
{
158
        m = other.m;
159
        ++(m->refs);
160
}
161
 
162
ScFace::~ScFace()
163
{
164
        if ( m && --(m->refs) == 0 ) {
165
                m->unload();
166
                delete m;
167
                m = 0;
168
        }
169
}
170
 
171
 
172
ScFace& ScFace::operator=(const ScFace& other)
173
{
7147 jghali 174
        if (m != other.m)
175
        {
7602 avox 176
                if (other.m)
177
                        ++(other.m->refs);
7147 jghali 178
                if ( m && --(m->refs) == 0 ) {
179
                        m->unload();
180
                        delete m;
181
                }
7413 jghali 182
                m = other.m;
5979 avox 183
        }
6733 avox 184
        replacedName = other.replacedName;
5985 avox 185
        return *this;
5979 avox 186
}
187
 
188
 
189
/** two ScFaces are equal if they either are both NULLFACEs or they
190
agree on family, style, variant and fontpath
191
*/
192
bool ScFace::operator==(const ScFace& other) const
193
{
6733 avox 194
        return replacedName == other.replacedName &&
195
                ( (isNone() && other.isNone() )
5979 avox 196
                         || (m == other.m)
197
                         || (m->family == other.m->family
198
                                 && m->style == other.m->style
199
                                 && m->variant == other.m->variant
200
                                 && m->fontFile == other.m->fontFile
201
                                 && m-> faceIndex == other.m->faceIndex) );
202
}
203
 
204
 
205
const ScFace& ScFace::none()
206
{
207
        static ScFace NONE;
208
        return NONE;
209
}
210
 
17777 jghali 211
QString ScFace::pdfAscentAsString() const
15363 jghali 212
{
213
        if (m->status == ScFace::UNKNOWN) {
214
                m->load();
215
        }
17777 jghali 216
        return m->pdfAscentAsString();
15363 jghali 217
}
218
 
17777 jghali 219
QString ScFace::pdfDescentAsString() const
15363 jghali 220
{
221
        if (m->status == ScFace::UNKNOWN) {
222
                m->load();
223
        }
17777 jghali 224
        return m->pdfDescentAsString();
15363 jghali 225
}
17777 jghali 226
QString ScFace::pdfCapHeightAsString() const
15363 jghali 227
{
228
        if (m->status == ScFace::UNKNOWN) {
229
                m->load();
230
        }
17777 jghali 231
        return m->pdfCapHeightAsString();
15363 jghali 232
}
233
 
17777 jghali 234
QString ScFace::pdfFontBBoxAsString() const
15363 jghali 235
{
236
        if (m->status == ScFace::UNKNOWN) {
237
                m->load();
238
        }
17777 jghali 239
        return m->pdfFontBBoxAsString();
15363 jghali 240
}
241
 
242
QString ScFace::italicAngleAsString() const
243
{
244
        if (m->status == ScFace::UNKNOWN) {
245
                m->load();
246
        }
247
        return m->ItalicAngleAsString();
248
}
249
 
13918 jghali 250
qreal ScFace::ascent(qreal sz) const
251
{
252
        if (m->status == ScFace::UNKNOWN) {
253
                m->load();
254
        }
255
        return m->ascent(sz);
256
}
5979 avox 257
 
13918 jghali 258
qreal ScFace::descent(qreal sz) const
259
{
260
        if (m->status == ScFace::UNKNOWN) {
261
                m->load();
262
        }
263
        return m->descent(sz);
264
}
265
qreal ScFace::xHeight(qreal sz) const
266
{
267
        if (m->status == ScFace::UNKNOWN) {
268
                m->load();
269
        }
270
        return m->xHeight(sz);
271
}
272
 
273
qreal ScFace::capHeight(qreal sz) const
274
{
275
        if (m->status == ScFace::UNKNOWN) {
276
                m->load();
277
        }
278
        return m->capHeight(sz);
279
}
280
 
281
qreal ScFace::height(qreal sz) const
282
{
283
        if (m->status == ScFace::UNKNOWN) {
284
                m->load();
285
        }
286
        return m->height(sz);
287
}
288
 
289
qreal ScFace::strikeoutPos(qreal sz) const
290
{
291
        if (m->status == ScFace::UNKNOWN) {
292
                m->load();
293
        }
294
        return m->strikeoutPos(sz);
295
}
296
 
297
qreal ScFace::underlinePos(qreal sz) const
298
{
299
        if (m->status == ScFace::UNKNOWN) {
300
                m->load();
301
        }
302
        return m->underlinePos(sz);
303
}
304
 
305
qreal ScFace::strokeWidth(qreal sz) const
306
{
307
        if (m->status == ScFace::UNKNOWN) {
308
                m->load();
309
        }
310
        return m->strokeWidth(sz);
311
}
312
 
313
qreal ScFace::maxAdvanceWidth(qreal sz) const
314
{
315
        if (m->status == ScFace::UNKNOWN) {
316
                m->load();
317
        }
318
        return m->maxAdvanceWidth(sz);
319
}
320
 
5979 avox 321
void ScFace::increaseUsage() const
322
{
323
        m->usage++;
324
}
325
 
326
 
327
void ScFace::decreaseUsage() const
328
{
329
        if (m->usage == 1)
330
                unload();
331
        m->usage--;
332
}
333
 
334
 
335
void ScFace::unload() const
336
{
337
        if (m->status >= ScFace::LOADED && usable()) {
338
                m->unload();
339
        }
340
        // clear caches
341
        m->m_glyphWidth.clear();
342
        m->m_glyphOutline.clear();
343
        m->m_cMap.clear();
344
        m->status = ScFace::UNKNOWN;
345
}
346
 
347
 
6978 avox 348
uint ScFace::emulateGlyph(QChar ch) const
6144 avox 349
{
350
        if (ch == SpecialChars::LINEBREAK || ch == SpecialChars::PARSEP
351
                || ch == SpecialChars::FRAMEBREAK || ch == SpecialChars::COLBREAK
6935 avox 352
                || ch == SpecialChars::TAB || ch == SpecialChars::SHYPHEN
353
                 || ch == SpecialChars::ZWSPACE || ch == SpecialChars::ZWNBSPACE)
6978 avox 354
                return CONTROL_GLYPHS + ch.unicode();
6144 avox 355
        else if (ch == SpecialChars::NBSPACE)
6978 avox 356
                return  m->char2CMap(QChar(' '));
6144 avox 357
        else if(ch == SpecialChars::NBHYPHEN)
6978 avox 358
                return  m->char2CMap(QChar('-'));
6144 avox 359
        else
360
                return 0;
361
}
362
 
363
 
5979 avox 364
uint ScFace::char2CMap(QChar ch) const
365
{
366
        if (m->status == ScFace::UNKNOWN) {
367
                m->load();
368
        }
9042 avox 369
 
370
        if (ch == SpecialChars::SHYPHEN)
371
                return emulateGlyph(ch);
372
 
6144 avox 373
        uint gl = m->char2CMap(ch);
9042 avox 374
 
6144 avox 375
        if (gl == 0)
376
                return emulateGlyph(ch);
377
        else
378
                return gl;
5979 avox 379
}
380
 
381
 
382
bool ScFace::canRender(QChar ch) const
383
{
384
        if (!usable())
385
                return false;
386
        else {
6978 avox 387
                uint gl = char2CMap(ch);    //  calls load()
9042 avox 388
                if (gl >= CONTROL_GLYPHS)   //  those are always empty
6978 avox 389
                        return true;
390
                else if (gl != 0) {
5979 avox 391
                        m->loadGlyph(gl);
392
                        return ! m->m_glyphOutline[gl].broken;
393
                }
394
                else  {
395
                        return false;
396
                }
397
        }
398
}
399
 
400
 
13162 malex 401
qreal ScFace::charWidth(QChar ch, qreal size, QChar ch2) const
5979 avox 402
{
403
        if (!canRender(ch)) // calls loadGlyph()
404
                return size;
405
        else if (ch.unicode() == 28 || ch.unicode() == 13 || ch.unicode() == 9)
406
                return ch.unicode() == 9 ? 1.0 : 0.0;
407
        else {
408
                uint gl1 = char2CMap(ch);
6144 avox 409
                uint gl2 = char2CMap(ch2);
13162 malex 410
                qreal width = glyphWidth(gl1, size);
5979 avox 411
                if (gl2 != 0)
412
                        width += glyphKerning(gl1, gl2, size);
13085 jghali 413
//              qDebug() << QString("scface::glyphkerning: %1_%2 = %3 (%4, %5)").arg(ch).arg(ch2).arg(glyphKerning(gl1, gl2,size)).arg(gl1).arg(gl2);
5979 avox 414
                return width;
415
        }
416
}
417
 
418
 
419
bool ScFace::EmbedFont(QString &str)
420
{
421
        if (m->status == ScFace::UNKNOWN) {
422
                m->load();
423
        }
424
        return m->EmbedFont(str);
425
}
426
 
427
 
6163 avox 428
bool ScFace::glyphNames(QMap<uint, std::pair<QChar, QString> >& gList)
5979 avox 429
{
430
        if (m->status == ScFace::UNKNOWN) {
431
                m->load();
432
        }
433
        return m->glyphNames(gList);
434
}
435
 
436
 
437
void ScFace::RawData(QByteArray & bb)
438
{
439
        if (m->status == ScFace::UNKNOWN) {
440
                m->load();
441
        }
442
        m->RawData(bb);
443
}
444
 
445
void ScFace::checkAllGlyphs()
446
{
447
        if (m->status == ScFace::UNKNOWN) {
448
                m->load();
449
        }
450
        if (m->status != ScFace::LOADED) {
451
                return;
452
        }
453
        for (uint gl=0; gl <= m->maxGlyph; ++gl) {
454
                if (! m->m_glyphWidth.contains(gl)) {
455
                        m->loadGlyph(gl);
456
                        m->m_glyphWidth.remove(gl);
457
                        m->m_glyphOutline.remove(gl);
458
                }
459
        }
460
}