Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 2003 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: ttfmain.c,v 1.34 2005/08/02 11:12:32 igor Exp $ */
18
/* A Free Type interface adapter. */
19
/* Uses code fragments from the FreeType project. */
20
 
21
#include "ttmisc.h"
22
#include "ttfoutl.h"
23
#include "ttfmemd.h"
24
 
25
#include "ttfinp.h"
26
#include "ttfsfnt.h"
27
#include "ttobjs.h"
28
#include "ttinterp.h"
29
#include "ttcalc.h"
30
 
31
private const bool skip_instructions = 0; /* Debug purpose only. */
32
 
33
typedef struct { 
34
    Fixed a, b, c, d, tx, ty;
35
} FixMatrix;
36
 
37
struct ttfSubGlyphUsage_s { 
38
    FixMatrix m;
39
    int index;
40
    int flags;
41
    short arg1, arg2;
42
};
43
 
44
/*------------------------------------------------------------------- */
45
 
46
private Fixed AVE(F26Dot6 a, F26Dot6 b)
47
{   return (a + b) / 2;
48
}
49
 
50
private F26Dot6 shortToF26Dot6(short a)
51
{   return (F26Dot6)a << 6;
52
}
53
 
54
private F26Dot6 floatToF26Dot6(float a)
55
{   return (F26Dot6)(a * (1 << 6) + 0.5);
56
}
57
 
58
private Fixed floatToF16Dot16(float a)
59
{   return (F26Dot6)(a * (1 << 16) + 0.5);
60
}
61
 
62
private void TransformF26Dot6PointFix(F26Dot6Point *pt, F26Dot6 dx, F26Dot6 dy, FixMatrix *m)
63
{   pt->x = MulDiv(dx, m->a, 65536) + MulDiv(dy, m->c, 65536) + (m->tx >> 10);
64
    pt->y = MulDiv(dx, m->b, 65536) + MulDiv(dy, m->d, 65536) + (m->ty >> 10);
65
}
66
 
67
private void TransformF26Dot6PointFloat(FloatPoint *pt, F26Dot6 dx, F26Dot6 dy, FloatMatrix *m)
68
{   pt->x = dx * m->a / 64 + dy * m->c / 64 + m->tx;
69
    pt->y = dx * m->b / 64 + dy * m->d / 64 + m->ty;
70
}
71
 
72
/*-------------------------------------------------------------------*/
73
 
74
private ttfPtrElem *ttfFont__get_table_ptr(ttfFont *f, char *id)
75
{
76
    if (!memcmp(id, "cvt ", 4))
77
	return &f->t_cvt_;
78
    if (!memcmp(id, "fpgm", 4))
79
	return &f->t_fpgm;
80
    if (!memcmp(id, "glyf", 4))
81
	return &f->t_glyf;
82
    if (!memcmp(id, "head", 4))
83
	return &f->t_head;
84
    if (!memcmp(id, "hhea", 4))
85
	return &f->t_hhea;
86
    if (!memcmp(id, "hmtx", 4))
87
	return &f->t_hmtx;
88
    if (!memcmp(id, "vhea", 4))
89
	return &f->t_vhea;
90
    if (!memcmp(id, "vmtx", 4))
91
	return &f->t_vmtx;
92
    if (!memcmp(id, "loca", 4))
93
	return &f->t_loca;
94
    if (!memcmp(id, "maxp", 4))
95
	return &f->t_maxp;
96
    if (!memcmp(id, "prep", 4))
97
	return &f->t_prep;
98
    if (!memcmp(id, "cmap", 4))
99
	return &f->t_cmap;
100
    return 0;
101
}
102
 
103
/*-------------------------------------------------------------------*/
104
 
105
TT_Error  TT_Set_Instance_CharSizes(TT_Instance  instance,
106
                                       TT_F26Dot6   charWidth,
107
                                       TT_F26Dot6   charHeight)
108
{ 
109
    PInstance  ins = instance.z;
110
 
111
    if ( !ins )
112
	return TT_Err_Invalid_Instance_Handle;
113
 
114
    if (charWidth < 1*64)
115
	charWidth = 1*64;
116
 
117
    if (charHeight < 1*64)
118
	charHeight = 1*64;
119
 
120
    ins->metrics.x_scale1 = charWidth;
121
    ins->metrics.y_scale1 = charHeight;
122
    ins->metrics.x_scale2 = ins->face->font->nUnitsPerEm;
123
    ins->metrics.y_scale2 = ins->face->font->nUnitsPerEm;
124
 
125
    if (ins->face->font->nFlags & 8) {
126
	ins->metrics.x_scale1 = (ins->metrics.x_scale1+32) & -64;
127
	ins->metrics.y_scale1 = (ins->metrics.y_scale1+32) & -64;
128
    }
129
 
130
    ins->metrics.x_ppem = ins->metrics.x_scale1 / 64;
131
    ins->metrics.y_ppem = ins->metrics.y_scale1 / 64;
132
 
133
    if (charWidth > charHeight)
134
	ins->metrics.pointSize = charWidth;
135
    else
136
	ins->metrics.pointSize = charHeight;
137
 
138
    ins->valid  = FALSE;
139
    return Instance_Reset(ins, FALSE);
140
  }
141
 
142
/*-------------------------------------------------------------------*/
143
 
144
int ttfInterpreter__obtain(ttfMemory *mem, ttfInterpreter **ptti)
145
{
146
    ttfInterpreter *tti;
147
 
148
    if (*ptti) {
149
	(*ptti)->lock++;
150
	return 0;
151
    }
152
    tti = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_ttfInterpreter, "ttfInterpreter__obtain");
153
    if (!tti)
154
	return fMemoryError;
155
    tti->usage = 0;
156
    tti->usage_size = 0;
157
    tti->ttf_memory = mem;
158
    tti->lock = 1;
159
    tti->exec = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TExecution_Context, "ttfInterpreter__obtain");
160
    if (!tti->exec) {
161
	mem->free(mem, tti, "ttfInterpreter__obtain");
162
	return fMemoryError;
163
    }
164
    memset(tti->exec, 0, sizeof(*tti->exec));
165
    *ptti = tti;
166
    return 0;
167
}
168
 
169
void ttfInterpreter__release(ttfInterpreter **ptti)
170
{
171
    ttfInterpreter *tti = *ptti;
172
    ttfMemory *mem = tti->ttf_memory;
173
 
174
    if(--tti->lock)
175
	return;
176
    mem->free(mem, tti->usage, "ttfInterpreter__release");
177
    mem->free(mem, tti->exec, "ttfInterpreter__release");
178
    mem->free(mem, *ptti, "ttfInterpreter__release");
179
    mem->free(mem, mem, "ttfInterpreter__release");
180
    *ptti = 0;
181
}
182
 
183
/*-------------------------------------------------------------------*/
184
 
185
void ttfFont__init(ttfFont *this, ttfMemory *mem, 
186
		    void (*DebugRepaint)(ttfFont *),
187
		    int (*DebugPrint)(ttfFont *, const char *s, ...))
188
{
189
    memset(this, 0, sizeof(*this));
190
    this->DebugRepaint = DebugRepaint;
191
    this->DebugPrint = DebugPrint;
192
}
193
 
194
void ttfFont__finit(ttfFont *this)
195
{   ttfMemory *mem = this->tti->ttf_memory;
196
 
197
    if (this->exec)
198
	Context_Destroy(this->exec);
199
    this->exec = NULL;
200
    if (this->inst)
201
	Instance_Destroy(this->inst);
202
    mem->free(mem, this->inst, "ttfFont__finit");
203
    this->inst = NULL;
204
    if (this->face)
205
	Face_Destroy(this->face);
206
    mem->free(mem, this->face, "ttfFont__finit");
207
    this->face = NULL;
208
}
209
 
210
#define MAX_SUBGLYPH_NESTING 3 /* Arbitrary. We need this because we don't want 
211
                                  a ttfOutliner__BuildGlyphOutline recursion 
212
				  while a glyph is loaded in ttfReader. */
213
 
214
FontError ttfFont__Open(ttfInterpreter *tti, ttfFont *this, ttfReader *r, 
215
				    unsigned int nTTC, float w, float h, 
216
				    bool design_grid)
217
{   char sVersion[4], sVersion0[4] = {0, 1, 0, 0};
218
    unsigned int nNumTables, i;
219
    TT_Error code;
220
    int k;
221
    TT_Instance I;
222
    ttfMemory *mem = tti->ttf_memory;
223
    F26Dot6 ww, hh;
224
 
225
    this->tti = tti;
226
    this->design_grid = design_grid;
227
    r->Read(r, sVersion, 4);
228
    if(!memcmp(sVersion, "ttcf", 4)) {
229
	unsigned int nFonts;
230
	unsigned int nPos = 0xbaadf00d; /* Quiet compiler. */
231
 
232
	r->Read(r, sVersion, 4);
233
	if(memcmp(sVersion, sVersion0, 4))
234
	    return fUnimplemented;
235
	nFonts = ttfReader__UInt(r);
236
	if (nFonts == 0)
237
	    return fBadFontData;
238
	if(nTTC >= nFonts)
239
	    return fTableNotFound;
240
	for(i = 0; i <= nTTC; i++)
241
	    nPos = ttfReader__UInt(r);
242
	r->Seek(r, nPos);
243
	r->Read(r, sVersion, 4);
244
    }
245
    if(memcmp(sVersion, sVersion0, 4) && memcmp(sVersion, "true", 4))
246
	return fUnimplemented;
247
    nNumTables    = ttfReader__UShort(r);
248
    ttfReader__UShort(r); /* nSearchRange */
249
    ttfReader__UShort(r); /* nEntrySelector */
250
    ttfReader__UShort(r); /* nRangeShift */
251
    for (i = 0; i < nNumTables; i++) {
252
	char sTag[5];
253
	unsigned int nOffset, nLength;
254
	ttfPtrElem *e;
255
 
256
	sTag[4] = 0;
257
	r->Read(r, sTag, 4);
258
	ttfReader__UInt(r); /* nCheckSum */
259
	nOffset = ttfReader__UInt(r);
260
	nLength = ttfReader__UInt(r);
261
	e = ttfFont__get_table_ptr(this, sTag);
262
	if (e != NULL) {
263
	    e->nPos = nOffset;
264
	    e->nLen = nLength;
265
	}
266
    }
267
    r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, flags));
268
    this->nFlags = ttfReader__UShort(r);
269
    r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, unitsPerEm));
270
    this->nUnitsPerEm = ttfReader__UShort(r);
271
    r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, indexToLocFormat));
272
    this->nIndexToLocFormat = ttfReader__UShort(r);
273
    r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, numGlyphs));
274
    this->nNumGlyphs = ttfReader__UShort(r);
275
    r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, maxComponentElements));
276
    this->nMaxComponents = ttfReader__UShort(r);
277
    if(this->nMaxComponents < 10)
278
	this->nMaxComponents = 10; /* work around DynaLab bug in lgoth.ttf */
279
    r->Seek(r, this->t_hhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
280
    this->nLongMetricsHorz = ttfReader__UShort(r);
281
    if (this->t_vhea.nPos != 0) {
282
	r->Seek(r, this->t_vhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
283
	this->nLongMetricsVert = ttfReader__UShort(r);
284
    } else
285
	this->nLongMetricsVert = 0;
286
    if (tti->usage_size < this->nMaxComponents * MAX_SUBGLYPH_NESTING) {
287
	tti->ttf_memory->free(tti->ttf_memory, tti->usage, "ttfFont__Open");
288
	tti->usage_size = 0;
289
	tti->usage = mem->alloc_bytes(mem, 
290
		sizeof(ttfSubGlyphUsage) * this->nMaxComponents * MAX_SUBGLYPH_NESTING, 
291
		"ttfFont__Open");
292
	if (tti->usage == NULL)
293
	    return fMemoryError;
294
	tti->usage_size = this->nMaxComponents * MAX_SUBGLYPH_NESTING;
295
    }
296
    this->face = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TFace, "ttfFont__Open");
297
    if (this->face == NULL)
298
	return fMemoryError;
299
    memset(this->face, 0, sizeof(*this->face));
300
    this->face->r = r;
301
    this->face->font = this;
302
    this->exec = tti->exec;
303
    code = Face_Create(this->face);
304
    if (code)
305
	return fMemoryError;
306
    code = r->Error(r);
307
    if (code < 0)
308
	return fBadFontData;
309
    this->inst = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TInstance, "ttfFont__Open");
310
    if (this->inst == NULL)
311
	return fMemoryError;
312
    memset(this->inst, 0, sizeof(*this->inst));
313
    code = Context_Create(this->exec, this->face); /* See comment in the implementation of Context_Create. */
314
    if (code == TT_Err_Out_Of_Memory)
315
	return fMemoryError;
316
    code = Instance_Create(this->inst, this->face);
317
    if (code == TT_Err_Out_Of_Memory)
318
	return fMemoryError;
319
    if (code)
320
	return fBadFontData;
321
    for(k = 0; k < this->face->cvtSize; k++)
322
	this->inst->cvt[k] = shortToF26Dot6(this->face->cvt[k]);
323
    code = Instance_Init(this->inst);
324
    if (code == TT_Err_Out_Of_Memory)
325
	return fMemoryError;
326
    if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
327
	return fBadInstruction;
328
    if (code)
329
	return fBadFontData;
330
    I.z = this->inst;
331
    if (design_grid)
332
	ww = hh = shortToF26Dot6(this->nUnitsPerEm);
333
    else {
334
	/* Round towards zero for a better view of mirrored characters : */
335
	ww = floatToF26Dot6(w);
336
	hh = floatToF26Dot6(h);
337
    }
338
    code = TT_Set_Instance_CharSizes(I, ww, hh);
339
    this->inst->metrics  = this->exec->metrics;
340
    if (code == TT_Err_Invalid_Engine)
341
	return fPatented;
342
    if (code == TT_Err_Out_Of_Memory)
343
	return fMemoryError;
344
    if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
345
	return fBadInstruction;
346
    if (code)
347
	return fBadFontData;
348
    return code;
349
}
350
 
351
private void ttfFont__StartGlyph(ttfFont *this)
352
{   Context_Load( this->exec, this->inst );
353
    if ( this->inst->GS.instruct_control & 2 )
354
	this->exec->GS = Default_GraphicsState;
355
    else
356
	this->exec->GS = this->inst->GS;
357
    this->tti->usage_top = 0;
358
}
359
 
360
private void ttfFont__StopGlyph(ttfFont *this)
361
{
362
    Context_Save(this->exec, this->inst);
363
}
364
 
365
/*-------------------------------------------------------------------*/
366
 
367
private void  mount_zone( PGlyph_Zone  source,
368
                          PGlyph_Zone  target )
369
{
370
    Int  np, nc;
371
 
372
    np = source->n_points;
373
    nc = source->n_contours;
374
 
375
    target->org_x = source->org_x + np;
376
    target->org_y = source->org_y + np;
377
    target->cur_x = source->cur_x + np;
378
    target->cur_y = source->cur_y + np;
379
    target->touch = source->touch + np;
380
 
381
    target->contours = source->contours + nc;
382
 
383
    target->n_points   = 0;
384
    target->n_contours = 0;
385
}
386
 
387
private void  Init_Glyph_Component( PSubglyph_Record    element,
388
                                   PSubglyph_Record    original,
389
                                   PExecution_Context  exec )
390
{
391
    element->index     = -1;
392
    element->is_scaled = FALSE;
393
    element->is_hinted = FALSE;
394
 
395
    if (original)
396
	mount_zone( &original->zone, &element->zone );
397
    else
398
	element->zone = exec->pts;
399
 
400
    element->zone.n_contours = 0;
401
    element->zone.n_points   = 0;
402
 
403
    element->arg1 = 0;
404
    element->arg2 = 0;
405
 
406
    element->element_flag = 0;
407
    element->preserve_pps = FALSE;
408
 
409
    element->transform.xx = 1 << 16;
410
    element->transform.xy = 0;
411
    element->transform.yx = 0;
412
    element->transform.yy = 1 << 16;
413
 
414
    element->transform.ox = 0;
415
    element->transform.oy = 0;
416
 
417
    element->leftBearing  = 0;
418
    element->advanceWidth = 0;
419
  }
420
 
421
private void  cur_to_org( Int  n, PGlyph_Zone  zone )
422
{
423
    Int  k;
424
 
425
    for ( k = 0; k < n; k++ )
426
	zone->org_x[k] = zone->cur_x[k];
427
 
428
    for ( k = 0; k < n; k++ )
429
	zone->org_y[k] = zone->cur_y[k];
430
}
431
 
432
private void  org_to_cur( Int  n, PGlyph_Zone  zone )
433
{
434
    Int  k;
435
 
436
    for ( k = 0; k < n; k++ )
437
	zone->cur_x[k] = zone->org_x[k];
438
 
439
    for ( k = 0; k < n; k++ )
440
	zone->cur_y[k] = zone->org_y[k];
441
}
442
 
443
 
444
/*-------------------------------------------------------------------*/
445
 
446
void ttfOutliner__init(ttfOutliner *this, ttfFont *f, ttfReader *r, ttfExport *exp, 
447
			bool bOutline, bool bFirst, bool bVertical) 
448
{
449
    this->r = r; 
450
    this->bOutline = bOutline;
451
    this->bFirst = bFirst;
452
    this->pFont = f;
453
    this->bVertical = bVertical;
454
    this->exp = exp;
455
}
456
 
457
private void MoveGlyphOutline(TGlyph_Zone *pts, int nOffset, ttfGlyphOutline *out, FixMatrix *m)
458
{   F26Dot6* x = pts->org_x + nOffset;
459
    F26Dot6* y = pts->org_y + nOffset;
460
    short count = out->pointCount;
461
    F26Dot6Point p;
462
 
463
    if (m->a == 65536 && m->b == 0 && 
464
	m->c == 0 && m->d == 65536 && 
465
	m->tx == 0 && m->ty == 0)
466
	return;
467
    for (; count != 0; --count) {
468
	TransformF26Dot6PointFix(&p, *x, *y, m);
469
	*x++ = p.x;
470
	*y++ = p.y;
471
    }
472
}
473
 
474
private FontError ttfOutliner__BuildGlyphOutlineAux(ttfOutliner *this, int glyphIndex, 
475
	    FixMatrix *m_orig, ttfGlyphOutline* gOutline)
476
{   ttfFont *pFont = this->pFont;
477
    ttfReader *r = this->r;
478
    ttfInterpreter *tti = pFont->tti;
479
    short sideBearing;
480
    FontError error = fNoError;
481
    short arg1, arg2;
482
    short count;
483
    unsigned int nMtxPos, nMtxGlyph = glyphIndex, nLongMetrics, i;
484
    unsigned short nAdvance;
485
    unsigned int nNextGlyphPtr = 0;
486
    unsigned int nPosBeg;
487
    TExecution_Context *exec = pFont->exec;
488
    TGlyph_Zone *pts = &exec->pts;
489
    TSubglyph_Record  subglyph;
490
    ttfSubGlyphUsage *usage = tti->usage + tti->usage_top;
491
    const byte *glyph = NULL;
492
    int glyph_size;
493
 
494
    if(this->bVertical && pFont->t_vhea.nPos && pFont->t_vmtx.nPos) {
495
	nLongMetrics = pFont->nLongMetricsVert;
496
	nMtxPos = pFont->t_vmtx.nPos;
497
    } else {
498
	nLongMetrics = pFont->nLongMetricsHorz;
499
	nMtxPos = pFont->t_hmtx.nPos;
500
    }
501
    if (this->bVertical && (!pFont->t_vhea.nPos || pFont->t_vmtx.nPos) && nMtxGlyph < nLongMetrics) {
502
	/* A bad font fix. */
503
	nMtxGlyph = nLongMetrics;
504
	if(nMtxGlyph >= pFont->nNumGlyphs)
505
	    nMtxGlyph = pFont->nNumGlyphs - 1;
506
    }
507
    if (nMtxGlyph < nLongMetrics) {
508
	r->Seek(r, nMtxPos + 4 * nMtxGlyph);
509
	nAdvance = ttfReader__Short(r);
510
	sideBearing = ttfReader__Short(r);
511
    } else {
512
	r->Seek(r, nMtxPos + 4 * (nLongMetrics - 1));
513
	nAdvance = ttfReader__Short(r);
514
	r->Seek(r, nMtxPos + 4 * nLongMetrics + 2 * (nMtxGlyph - nLongMetrics));
515
	sideBearing = ttfReader__Short(r);
516
    }
517
    if (r->Error(r))
518
	goto errex;
519
    gOutline->sideBearing = shortToF26Dot6(sideBearing);
520
    gOutline->advance.x = shortToF26Dot6(nAdvance);
521
    gOutline->advance.y = 0;
522
    this->bFirst = FALSE;
523
 
524
 
525
    if (!this->bOutline)
526
	return fNoError;
527
    if (!r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size))
528
	return fGlyphNotFound;
529
    if (r->Eof(r)) {
530
	r->ReleaseGlyph(r, glyphIndex);
531
	gOutline->xMinB = gOutline->yMinB = 0;
532
	gOutline->xMaxB = gOutline->yMaxB = 0;
533
	return fNoError;
534
    }
535
    if (r->Error(r))
536
	goto errex;
537
    nPosBeg = r->Tell(r);
538
 
539
    gOutline->contourCount = ttfReader__Short(r);
540
    subglyph.bbox.xMin = ttfReader__Short(r);
541
    subglyph.bbox.yMin = ttfReader__Short(r);
542
    subglyph.bbox.xMax = ttfReader__Short(r);
543
    subglyph.bbox.yMax = ttfReader__Short(r);
544
 
545
    gOutline->xMinB = subglyph.bbox.xMin;
546
    gOutline->yMinB = subglyph.bbox.yMin;
547
    gOutline->xMaxB = subglyph.bbox.xMax;
548
    gOutline->yMaxB = subglyph.bbox.yMax;
549
 
550
    /* FreeType stuff beg */
551
    Init_Glyph_Component(&subglyph, NULL, pFont->exec);
552
    subglyph.leftBearing = sideBearing;
553
    subglyph.advanceWidth = nAdvance;
554
    subglyph.pp1.x = subglyph.bbox.xMin - sideBearing;
555
    subglyph.pp1.y = 0;
556
    subglyph.pp2.x = subglyph.pp1.x + nAdvance;
557
    subglyph.pp2.y = 0;
558
    /* FreeType stuff end */
559
 
560
    if (gOutline->contourCount == 0)
561
	gOutline->pointCount = 0;
562
    else if (gOutline->contourCount == -1) {
563
	unsigned short flags, index, bHaveInstructions = 0;
564
	unsigned int nUsage = 0;
565
	unsigned int nPos;
566
	unsigned int n_ins;
567
 
568
	gOutline->bCompound = TRUE;
569
	if (tti->usage_top + pFont->nMaxComponents > tti->usage_size)
570
	    return fBadFontData;
571
	gOutline->contourCount = gOutline->pointCount = 0;
572
	do { 
573
	    FixMatrix m;
574
	    ttfSubGlyphUsage *e;
575
 
576
	    if (nUsage >= pFont->nMaxComponents) {
577
		error = fMemoryError; goto ex;
578
	    }
579
	    flags = ttfReader__UShort(r);
580
	    index = ttfReader__UShort(r);
581
	    bHaveInstructions |= (flags & WE_HAVE_INSTRUCTIONS);
582
	    if (flags & ARG_1_AND_2_ARE_WORDS) {
583
		arg1 = ttfReader__Short(r);
584
		arg2 = ttfReader__Short(r);
585
            } else {
586
		if (flags & ARGS_ARE_XY_VALUES) {
587
		    /* offsets are signed */
588
		    arg1 = ttfReader__SignedByte(r);
589
		    arg2 = ttfReader__SignedByte(r);
590
                } else { /* anchor points are unsigned */
591
		    arg1 = ttfReader__Byte(r);
592
		    arg2 = ttfReader__Byte(r);
593
                }
594
            }
595
	    m.b = m.c = m.tx = m.ty = 0;
596
	    if (flags & WE_HAVE_A_SCALE)
597
		m.a = m.d = (Fixed)ttfReader__Short(r) << 2;
598
	    else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
599
		m.a = (Fixed)ttfReader__Short(r) << 2;
600
		m.d = (Fixed)ttfReader__Short(r) << 2;
601
	    } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
602
		m.a = (Fixed)ttfReader__Short(r)<<2;
603
		m.b = (Fixed)ttfReader__Short(r)<<2;
604
		m.c = (Fixed)ttfReader__Short(r)<<2;
605
		m.d = (Fixed)ttfReader__Short(r)<<2;
606
            } else 
607
		m.a = m.d = 65536;
608
	    e = &usage[nUsage];
609
	    e->m = m;
610
	    e->index = index;
611
	    e->arg1 = arg1;
612
	    e->arg2 = arg2;
613
	    e->flags = flags;
614
	    nUsage++;
615
        } while (flags & MORE_COMPONENTS);
616
	/* Some fonts have bad WE_HAVE_INSTRUCTIONS, so use nNextGlyphPtr : */
617
	if (r->Error(r))
618
	    goto errex;
619
	nPos = r->Tell(r);
620
	n_ins = ((!r->Eof(r) && (bHaveInstructions || nPos < nNextGlyphPtr)) ? ttfReader__UShort(r) : 0);
621
	nPos = r->Tell(r);
622
	r->ReleaseGlyph(r, glyphIndex);
623
	glyph = NULL;
624
	for (i = 0; i < nUsage; i++) {
625
	    ttfGlyphOutline out;
626
	    ttfSubGlyphUsage *e = &usage[i];
627
	    int j;
628
	    TT_Error code;
629
	    int nPointsStored = this->nPointsTotal, nContoursStored = this->nContoursTotal;
630
 
631
	    out.contourCount = 0;
632
	    out.pointCount = 0;
633
	    out.bCompound = FALSE;
634
	    pts->org_x += nPointsStored;
635
	    pts->org_y += nPointsStored;
636
	    pts->cur_x += nPointsStored;
637
	    pts->cur_y += nPointsStored;
638
	    pts->touch += nPointsStored;
639
	    pts->contours += nContoursStored;
640
	    tti->usage_top += nUsage;
641
	    code = ttfOutliner__BuildGlyphOutlineAux(this, e->index, m_orig, &out);
642
	    pts->org_x -= nPointsStored;
643
	    pts->org_y -= nPointsStored;
644
	    pts->cur_x -= nPointsStored;
645
	    pts->cur_y -= nPointsStored;
646
	    pts->touch -= nPointsStored;
647
	    tti->usage_top -= nUsage;
648
	    pts->contours -= nContoursStored;
649
	    if (code == fPatented)
650
		error = code;
651
	    else if (code != fNoError) {
652
		error = code;
653
		goto ex;
654
	    }
655
	    if (flags & ARGS_ARE_XY_VALUES) {
656
		e->m.tx = Scale_X( &exec->metrics, e->arg1 ) << 10;
657
		e->m.ty = Scale_Y( &exec->metrics, e->arg2 ) << 10;
658
            } else {
659
		e->m.tx = (pts->org_x[e->arg1] - pts->org_x[gOutline->pointCount + e->arg2]) << 10;
660
		e->m.ty = (pts->org_y[e->arg1] - pts->org_y[gOutline->pointCount + e->arg2]) << 10;
661
            }
662
	    MoveGlyphOutline(pts, nPointsStored, &out, &e->m);
663
	    for (j = nContoursStored; j < out.contourCount + nContoursStored; j++)
664
		pts->contours[j] += nPointsStored;
665
	    gOutline->contourCount += out.contourCount;
666
	    gOutline->pointCount += out.pointCount;
667
	    if(e->flags & USE_MY_METRICS) {
668
		gOutline->advance.x = out.advance.x; 
669
		gOutline->sideBearing = out.sideBearing;
670
            }
671
        }
672
	if (!skip_instructions && n_ins &&
673
		!(pFont->inst->GS.instruct_control & 1)) {
674
	    TT_Error code;
675
 
676
	    r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size);
677
	    if (r->Error(r))
678
		goto errex;
679
	    if (nPos + n_ins > glyph_size)
680
		goto errex;
681
	    code = Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
682
	    if (!code) {
683
		int nPoints = gOutline->pointCount + 2;
684
		int k;
685
		F26Dot6 x;
686
 
687
		exec->pts = subglyph.zone;
688
		pts->n_points = nPoints;
689
		pts->n_contours = gOutline->contourCount;
690
		/* add phantom points : */
691
		pts->org_x[nPoints - 2] = Scale_X(&exec->metrics, subglyph.pp1.x);
692
		pts->org_y[nPoints - 2] = Scale_Y(&exec->metrics, subglyph.pp1.y);
693
		pts->org_x[nPoints - 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
694
		pts->org_y[nPoints - 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
695
		pts->touch[nPoints - 1] = 0;
696
		pts->touch[nPoints - 2] = 0;
697
		/* if hinting, round the phantom points (not sure) : */
698
		x = pts->org_x[nPoints - 2];
699
		x = ((x + 32) & -64) - x;
700
		if (x)
701
		    for (k = 0; k < nPoints; k++)
702
			pts->org_x[k] += x;
703
    		pts->cur_x[nPoints - 1] = (pts->cur_x[nPoints - 1] + 32) & -64;
704
		for (k = 0; k < nPoints; k++)
705
		    pts->touch[k] = pts->touch[k] & TT_Flag_On_Curve;
706
		org_to_cur(nPoints, pts);
707
		exec->is_composite = TRUE;
708
		if (pFont->patented)
709
		    code = TT_Err_Invalid_Engine;
710
		else
711
		    code = Context_Run(exec, FALSE);
712
		if (!code)
713
		    cur_to_org(nPoints, pts);
714
		else if (code == TT_Err_Invalid_Engine)
715
		    error = fPatented;
716
		else
717
		    error = fBadFontData;
718
            }
719
	    Unset_CodeRange(exec);
720
	    Clear_CodeRange(exec, TT_CodeRange_Glyph);
721
        }
722
    } else if (gOutline->contourCount > 0) {
723
	uint16 i;
724
	int nPoints;
725
	bool bInsOK;
726
	byte *onCurve, *stop, flag;
727
	short *endPoints;
728
	unsigned int nPos;
729
	unsigned int n_ins;
730
 
731
	if (this->nContoursTotal + gOutline->contourCount > exec->n_contours) {
732
	    error = fBadFontData; goto ex;
733
	}
734
	endPoints = pts->contours;
735
	for (i = 0; i < gOutline->contourCount; i++)
736
	    endPoints[i] = ttfReader__Short(r);
737
	for (i = 1; i < gOutline->contourCount; i++)
738
	    if (endPoints[i - 1] >= endPoints[i]) {
739
		error = fBadFontData; goto ex;
740
	    }
741
	nPoints = gOutline->pointCount = endPoints[gOutline->contourCount - 1] + 1;
742
	if (this->nPointsTotal + nPoints + 2 > exec->n_points) {
743
	    error = fBadFontData; goto ex;
744
	}
745
	n_ins = ttfReader__Short(r);
746
	nPos = r->Tell(r);
747
	r->Seek(r, nPos + n_ins);
748
	if (r->Error(r))
749
	    goto errex;
750
	bInsOK = !Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
751
	onCurve = pts->touch;
752
	stop = onCurve + gOutline->pointCount;
753
 
754
	while (onCurve < stop) {
755
	    *onCurve++ = flag = ttfReader__Byte(r);
756
	    if (flag & REPEAT_FLAGS) {
757
		count = ttfReader__Byte(r);
758
		for (--count; count >= 0; --count)
759
		    *onCurve++ = flag;
760
            }
761
        }
762
	/*  Lets do X */
763
	{   short coord = (this->bVertical ? 0 : sideBearing - subglyph.bbox.xMin);
764
	    F26Dot6* x = pts->org_x;
765
	    onCurve = pts->touch;
766
	    while (onCurve < stop) {
767
		if ((flag = *onCurve++) & XSHORT) {
768
		    if (flag & SHORT_X_IS_POS)
769
			coord += ttfReader__Byte(r);
770
		    else
771
		    coord -= ttfReader__Byte(r);
772
		} else if (!(flag & NEXT_X_IS_ZERO))
773
		    coord += ttfReader__Short(r);
774
		*x++ = Scale_X(&exec->metrics, coord);
775
	    }
776
	}
777
	/*  Lets do Y */
778
	{   short coord = 0;
779
	    F26Dot6* y = pts->org_y;
780
	    onCurve = pts->touch;
781
	    while (onCurve < stop) {
782
		if((flag = *onCurve) & YSHORT)
783
		    if ( flag & SHORT_Y_IS_POS )
784
			coord += ttfReader__Byte(r);
785
		    else
786
			coord -= ttfReader__Byte(r);
787
		else if(!(flag & NEXT_Y_IS_ZERO))
788
		    coord += ttfReader__Short(r);
789
		*y++ = Scale_Y( &exec->metrics, coord );
790
 
791
		/*  Filter off the extra bits */
792
		*onCurve++ = flag & ONCURVE;
793
	    }
794
	}
795
        MoveGlyphOutline(pts, 0, gOutline, m_orig);
796
	this->nContoursTotal += gOutline->contourCount;
797
	this->nPointsTotal += nPoints;
798
	if (!skip_instructions &&
799
		!r->Error(r) && n_ins && bInsOK && !(pFont->inst->GS.instruct_control & 1)) {
800
	    TGlyph_Zone *pts = &exec->pts;
801
	    int k;
802
	    F26Dot6 x;
803
	    TT_Error code;
804
 
805
	    exec->is_composite = FALSE;
806
	    /* add phantom points : */
807
	    pts->org_x[nPoints    ] = Scale_X(&exec->metrics, subglyph.pp1.x);
808
	    pts->org_y[nPoints    ] = Scale_Y(&exec->metrics, subglyph.pp1.y);
809
	    pts->org_x[nPoints + 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
810
	    pts->org_y[nPoints + 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
811
	    pts->touch[nPoints    ] = 0;
812
	    pts->touch[nPoints + 1] = 0;
813
	    pts->n_points   = nPoints + 2;
814
	    pts->n_contours = gOutline->contourCount;
815
	    /* if hinting, round the phantom points (not sure) : */
816
	    x = pts->org_x[nPoints];
817
	    x = ((x + 32) & -64) - x;
818
	    if (x)
819
		for (k = 0; k < nPoints + 2; k++)
820
		    pts->org_x[k] += x;
821
	    pts->cur_x[nPoints + 1] = (pts->cur_x[nPoints + 1] + 32) & -64;
822
	    org_to_cur(nPoints + 2, pts);
823
	    exec->is_composite = FALSE;
824
	    for (k = 0; k < nPoints + 2; k++)
825
		pts->touch[k] &= TT_Flag_On_Curve;
826
	    if (pFont->patented)
827
		code = TT_Err_Invalid_Engine;
828
	    else
829
		code = Context_Run(exec, FALSE );
830
	    if (!code)
831
		cur_to_org(nPoints + 2, pts);
832
	    else if (code == TT_Err_Invalid_Engine)
833
		error = fPatented;
834
	    else
835
		error = fBadInstruction;
836
	    gOutline->sideBearing = subglyph.bbox.xMin - subglyph.pp1.x;
837
	    gOutline->advance.x = subglyph.pp2.x - subglyph.pp1.x;
838
        }
839
        Unset_CodeRange(exec);
840
        Clear_CodeRange(exec, TT_CodeRange_Glyph);
841
    } else
842
	error = fBadFontData;
843
    goto ex;
844
errex:;
845
    error = fBadFontData;
846
ex:;
847
    r->ReleaseGlyph(r, glyphIndex);
848
    return error;
849
}
850
 
851
private FontError ttfOutliner__BuildGlyphOutline(ttfOutliner *this, int glyphIndex, 
852
	    float orig_x, float orig_y, ttfGlyphOutline* gOutline)
853
{
854
    FixMatrix m_orig = {1 << 16, 0, 0, 1 << 16, 0, 0};
855
 
856
    /* Round towards zero like old character coordinate conversions do. */
857
    m_orig.tx = floatToF16Dot16(orig_x);
858
    m_orig.ty = floatToF16Dot16(orig_y);
859
    return ttfOutliner__BuildGlyphOutlineAux(this, glyphIndex, &m_orig, gOutline);
860
}
861
 
862
 
863
#define AVECTOR_BUG 1 /* Work around a bug in AVector fonts. */
864
 
865
void ttfOutliner__DrawGlyphOutline(ttfOutliner *this)
866
{   ttfGlyphOutline* out = &this->out;
867
    FloatMatrix *m = &this->post_transform;
868
    ttfFont *pFont = this->pFont;
869
    ttfExport *exp = this->exp;
870
    TExecution_Context *exec = pFont->exec;
871
    TGlyph_Zone *pts = &exec->pts;
872
    short* endP = pts->contours;
873
    byte* onCurve = pts->touch;
874
    F26Dot6* x = pts->org_x;
875
    F26Dot6* y = pts->org_y;
876
    F26Dot6 px, py;
877
    short sp, ctr;
878
    FloatPoint p0, p1, p2, p3;
879
 
880
#   if AVECTOR_BUG
881
	short xMinB = out->xMinB >> 6, xMaxB=out->xMaxB >> 6;
882
	short yMinB = out->yMinB >> 6, yMaxB=out->yMaxB >> 6;
883
	short expand=pFont->nUnitsPerEm*2;
884
	F26Dot6 xMin, xMax, yMin, yMax;
885
 
886
	xMinB -= expand;
887
	yMinB -= expand;
888
	xMaxB += expand;
889
	yMaxB += expand;
890
	xMin = Scale_X(&exec->metrics, xMinB);
891
	xMax = Scale_X(&exec->metrics, xMaxB);
892
	yMin = Scale_X(&exec->metrics, yMinB);
893
	yMax = Scale_X(&exec->metrics, yMaxB);
894
#   endif
895
 
896
    TransformF26Dot6PointFloat(&p1, out->advance.x, out->advance.y, m);
897
    p1.x -= this->post_transform.tx;
898
    p1.y -= this->post_transform.ty;
899
    exp->SetWidth(exp, &p1);
900
    sp = -1;
901
    for (ctr = out->contourCount; ctr != 0; --ctr) {
902
	short pt, pts = *endP - sp;
903
	short ep = pts - 1;
904
 
905
	if (pts < 3) {
906
	    x += pts;
907
	    y += pts;
908
	    onCurve += pts;
909
	    sp = *endP++;
910
	    continue;   /* skip 1 and 2 point contours */
911
        }
912
 
913
	if (exp->bPoints) {
914
	    for (pt = 0; pt <= ep; pt++) {
915
		px = x[pt], py = y[pt];
916
#		if AVECTOR_BUG
917
		    if (x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
918
			short prevIndex = pt == 0 ? ep : pt - 1;
919
			short nextIndex = pt == ep ? 0 : pt + 1;
920
			if (nextIndex > ep)
921
			    nextIndex = 0;
922
			px=AVE(x[prevIndex], x[nextIndex]);
923
			py=AVE(y[prevIndex], y[nextIndex]);
924
		    }
925
#		endif
926
		TransformF26Dot6PointFloat(&p0, px, py, m);
927
		exp->Point(exp, &p0, onCurve[pt], !pt);
928
            }
929
        }
930
 
931
	if (exp->bOutline) {
932
	    pt = 0;
933
	    if(onCurve[ep] & 1) {
934
		px = x[ep];
935
		py = y[ep];
936
            } else if (onCurve[0] & 1) {
937
		px = x[0];
938
		py = y[0];
939
		pt = 1;
940
            } else {
941
		px = AVE(x[0], x[ep]);
942
		py = AVE(y[0], y[ep]);
943
            }
944
	    this->ppx = px; this->ppy = py;
945
	    TransformF26Dot6PointFloat(&p0, px, py, m);
946
	    exp->MoveTo(exp, &p0);
947
 
948
	    for (; pt <= ep; pt++) {
949
		short prevIndex = pt == 0 ? ep : pt - 1;
950
		short nextIndex = pt == ep ? 0 : pt + 1;
951
		if (onCurve[pt] & 1) {
952
		    if (onCurve[prevIndex] & 1) {
953
			px = x[pt];
954
			py = y[pt];
955
			if (this->ppx != px || this->ppy != py) {
956
			    TransformF26Dot6PointFloat(&p1, px, py, m);
957
			    exp->LineTo(exp, &p1);
958
			    this->ppx = px; this->ppy = py;
959
			    p0 = p1;
960
                        }
961
                    }
962
                } else { 
963
		    F26Dot6 prevX, prevY, nextX, nextY;
964
 
965
		    px = x[pt];
966
		    py = y[pt];
967
#		    if AVECTOR_BUG
968
			if(x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
969
			    px=AVE(x[prevIndex], x[nextIndex]);
970
			    py=AVE(y[prevIndex], y[nextIndex]);
971
			}
972
#		    endif
973
		    if (onCurve[prevIndex] & 1) {
974
			prevX = x[prevIndex];
975
			prevY = y[prevIndex];
976
                    } else {
977
			prevX = AVE(x[prevIndex], px);
978
			prevY = AVE(y[prevIndex], py);
979
                    }
980
		    if (onCurve[nextIndex] & 1) {
981
			nextX = x[nextIndex];
982
			nextY = y[nextIndex];
983
                    } else {
984
			nextX = AVE(px, x[nextIndex]);
985
			nextY = AVE(py, y[nextIndex]);
986
                    }
987
		    if (this->ppx != nextX || this->ppy != nextY) {
988
			double dx1, dy1, dx2, dy2, dx3, dy3;
989
			const double prec = 1e-6;
990
 
991
			TransformF26Dot6PointFloat(&p1, (prevX + (px << 1)) / 3, (prevY + (py << 1)) / 3, m);
992
			TransformF26Dot6PointFloat(&p2, (nextX + (px << 1)) / 3, (nextY + (py << 1)) / 3, m);
993
			TransformF26Dot6PointFloat(&p3, nextX, nextY, m);
994
			dx1 = p1.x - p0.x, dy1 = p1.y - p0.y;
995
			dx2 = p2.x - p0.x, dy2 = p2.y - p0.y;
996
			dx3 = p3.x - p0.x, dy3 = p3.y - p0.y;
997
			if (fabs(dx1 * dy3 - dy1 * dx3) > prec * fabs(dx1 * dx3 - dy1 * dy3) || 
998
			    fabs(dx2 * dy3 - dy2 * dx3) > prec * fabs(dx2 * dx3 - dy2 * dy3))
999
			    exp->CurveTo(exp, &p1, &p2, &p3);
1000
			else
1001
			    exp->LineTo(exp, &p3);
1002
			this->ppx = nextX; this->ppy = nextY;
1003
			p0 = p3;
1004
                    }
1005
                }
1006
            }
1007
	    exp->Close(exp);
1008
        }
1009
	x += pts;
1010
	y += pts;
1011
	onCurve += pts;
1012
	sp = *endP++;
1013
    }
1014
}
1015
 
1016
FontError ttfOutliner__Outline(ttfOutliner *this, int glyphIndex,
1017
	float orig_x, float orig_y, FloatMatrix *m1)
1018
{   ttfFont *pFont = this->pFont;
1019
    FontError error;
1020
 
1021
    this->post_transform = *m1;
1022
    this->out.contourCount = 0;
1023
    this->out.pointCount = 0;
1024
    this->out.bCompound = FALSE;
1025
    this->nPointsTotal = 0;
1026
    this->nContoursTotal = 0;
1027
    this->out.advance.x = this->out.advance.y = 0;
1028
    ttfFont__StartGlyph(pFont);
1029
    error = ttfOutliner__BuildGlyphOutline(this, glyphIndex, orig_x, orig_y, &this->out);
1030
    ttfFont__StopGlyph(pFont);
1031
    if (pFont->nUnitsPerEm <= 0)
1032
	pFont->nUnitsPerEm = 1024;
1033
    if (pFont->design_grid) {
1034
	this->post_transform.a /= pFont->nUnitsPerEm;
1035
	this->post_transform.b /= pFont->nUnitsPerEm;
1036
	this->post_transform.c /= pFont->nUnitsPerEm;
1037
	this->post_transform.d /= pFont->nUnitsPerEm;
1038
    }
1039
    if (error != fNoError && error != fPatented)
1040
	return error;
1041
    return error;
1042
}