Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/gs/src/gxttfb.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1992, 1995, 1997, 1999 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: gxttfb.c,v 1.37 2005/08/02 11:12:32 igor Exp $ */
18
/* A bridge to True Type interpreter. */
19
 
20
#include "gx.h"
21
#include "gxfont.h"
22
#include "gxfont42.h"
23
#include "gxttfb.h"
24
#include "gxfixed.h"
25
#include "gxpath.h"
26
#include "gxfcache.h"
27
#include "gxmatrix.h"
28
#include "gxhintn.h"
29
#include "gzpath.h"
30
#include "ttfmemd.h"
31
#include "gsstruct.h"
32
#include "gserrors.h"
33
#include "gsfont.h"
34
#include "gdebug.h"
35
#include "memory_.h"
36
#include "math_.h"
37
#include "gxistate.h"
38
#include "gxpaint.h"
39
#include "gzspotan.h"
40
#include <stdarg.h>
41
 
42
gs_public_st_composite(st_gx_ttfReader, gx_ttfReader,
43
    "gx_ttfReader", gx_ttfReader_enum_ptrs, gx_ttfReader_reloc_ptrs);
44
 
45
private 
46
ENUM_PTRS_WITH(gx_ttfReader_enum_ptrs, gx_ttfReader *mptr)
47
    {
48
	/* The fields 'pfont' and 'glyph_data' may contain pointers from global 
49
	   to local memory ( see a comment in gxttfb.h).
50
	   They must be NULL when a garbager is invoked.
51
	   Due to that we don't enumerate and don't relocate them.
52
	 */
53
	DISCARD(mptr);
54
	return 0;
55
    }
56
    ENUM_PTR(0, gx_ttfReader, memory);
57
ENUM_PTRS_END
58
 
59
private RELOC_PTRS_WITH(gx_ttfReader_reloc_ptrs, gx_ttfReader *mptr)
60
    DISCARD(mptr);
61
    RELOC_PTR(gx_ttfReader, memory);
62
RELOC_PTRS_END
63
 
64
private bool gx_ttfReader__Eof(ttfReader *this)
65
{
66
    gx_ttfReader *r = (gx_ttfReader *)this;
67
 
68
    if (r->extra_glyph_index != -1)
69
	return r->pos >= r->glyph_data.bits.size;
70
    /* We can't know whether pfont->data.string_proc has more bytes,
71
       so we never report Eof for it. */
72
    return false;
73
}
74
 
75
private void gx_ttfReader__Read(ttfReader *this, void *p, int n)
76
{
77
    gx_ttfReader *r = (gx_ttfReader *)this;
78
    const byte *q;
79
 
80
    if (!r->error) {
81
	if (r->extra_glyph_index != -1) {
82
	    q = r->glyph_data.bits.data + r->pos;
83
	    r->error = (r->glyph_data.bits.size - r->pos < n ? 
84
			    gs_note_error(gs_error_invalidfont) : 0);
85
	} else {
86
	    r->error = r->pfont->data.string_proc(r->pfont, (ulong)r->pos, (ulong)n, &q);
87
	    if (r->error > 0) {
88
		/* Need a loop with pfont->data.string_proc . Not implemented yet. */
89
		r->error = gs_note_error(gs_error_unregistered);
90
	    }
91
	}
92
    }
93
    if (r->error) {
94
	memset(p, 0, n);
95
	return;
96
    }
97
    memcpy(p, q, n);
98
    r->pos += n;
99
}
100
 
101
private void gx_ttfReader__Seek(ttfReader *this, int nPos)
102
{
103
    gx_ttfReader *r = (gx_ttfReader *)this;
104
 
105
    r->pos = nPos;
106
}
107
 
108
private int gx_ttfReader__Tell(ttfReader *this)
109
{
110
    gx_ttfReader *r = (gx_ttfReader *)this;
111
 
112
    return r->pos;
113
}
114
 
115
private bool gx_ttfReader__Error(ttfReader *this)
116
{
117
    gx_ttfReader *r = (gx_ttfReader *)this;
118
 
119
    return r->error;
120
}
121
 
122
private int gx_ttfReader__LoadGlyph(ttfReader *this, int glyph_index, const byte **p, int *size)
123
{
124
    gx_ttfReader *r = (gx_ttfReader *)this;
125
    gs_font_type42 *pfont = r->pfont;
126
    int code;
127
 
128
    if (r->extra_glyph_index != -1)
129
	return 0; /* We only maintain a single glyph buffer.
130
	             It's enough because ttfOutliner__BuildGlyphOutline
131
		     is optimized for that, and pfont->data.get_outline 
132
		     implements a charstring cache. */
133
    r->glyph_data.memory = pfont->memory;
134
    code = pfont->data.get_outline(pfont, (uint)glyph_index, &r->glyph_data);
135
    r->extra_glyph_index = glyph_index;
136
    r->pos = 0;
137
    if (code < 0)
138
	r->error = code;
139
    else if (code > 0) {
140
	/* Should not happen. */
141
	r->error = gs_note_error(gs_error_unregistered);
142
    } else {
143
	*p = r->glyph_data.bits.data;
144
	*size = r->glyph_data.bits.size;
145
    }
146
    return 2; /* found */
147
}
148
 
149
private void gx_ttfReader__ReleaseGlyph(ttfReader *this, int glyph_index)
150
{
151
    gx_ttfReader *r = (gx_ttfReader *)this;
152
 
153
    if (r->extra_glyph_index != glyph_index)
154
	return;
155
    r->extra_glyph_index = -1;
156
    gs_glyph_data_free(&r->glyph_data, "gx_ttfReader__ReleaseExtraGlyph");
157
}
158
 
159
private void gx_ttfReader__Reset(gx_ttfReader *this)
160
{
161
    if (this->extra_glyph_index != -1) {
162
	this->extra_glyph_index = -1;
163
	gs_glyph_data_free(&this->glyph_data, "gx_ttfReader__Reset");
164
    }
165
    this->error = false;
166
    this->pos = 0;
167
}
168
 
169
gx_ttfReader *gx_ttfReader__create(gs_memory_t *mem)
170
{
171
    gx_ttfReader *r = gs_alloc_struct(mem, gx_ttfReader, &st_gx_ttfReader, "gx_ttfReader__create");
172
 
173
    if (r != NULL) {
174
	r->super.Eof = gx_ttfReader__Eof;
175
	r->super.Read = gx_ttfReader__Read;
176
	r->super.Seek = gx_ttfReader__Seek;
177
	r->super.Tell = gx_ttfReader__Tell;
178
	r->super.Error = gx_ttfReader__Error;
179
	r->super.LoadGlyph = gx_ttfReader__LoadGlyph;
180
	r->super.ReleaseGlyph = gx_ttfReader__ReleaseGlyph;
181
	r->pos = 0;
182
	r->error = false;
183
	r->extra_glyph_index = -1;
184
	memset(&r->glyph_data, 0, sizeof(r->glyph_data));
185
	r->pfont = NULL;
186
	r->memory = mem;
187
	gx_ttfReader__Reset(r);
188
    }
189
    return r;
190
}
191
 
192
void gx_ttfReader__destroy(gx_ttfReader *this)
193
{
194
    gs_free_object(this->memory, this, "gx_ttfReader__destroy");
195
}
196
 
197
void gx_ttfReader__set_font(gx_ttfReader *this, gs_font_type42 *pfont)
198
{
199
    this->pfont = pfont;
200
}
201
 
202
 
203
/*----------------------------------------------*/
204
 
205
private void DebugRepaint(ttfFont *ttf)
206
{
207
}
208
 
209
private int DebugPrint(ttfFont *ttf, const char *fmt, ...)
210
{
211
    char buf[500];
212
    va_list args;
213
    int count;
214
 
215
    if (gs_debug_c('Y')) {
216
	va_start(args, fmt);
217
	count = vsprintf(buf, fmt, args);
218
	/* NB: moved debug output from stdout to stderr
219
	 */
220
	errwrite(buf, count);
221
	va_end(args);
222
    }
223
    return 0;
224
}
225
 
226
private void WarnBadInstruction(gs_font_type42 *pfont, int glyph_index)
227
{
228
    char buf[gs_font_name_max + 1];
229
    int l;
230
    gs_font_type42 *base_font = pfont;
231
 
232
    while ((gs_font_type42 *)base_font->base != base_font)
233
	base_font = (gs_font_type42 *)base_font->base;
234
    if (!base_font->data.warning_bad_instruction) {
235
	l = min(sizeof(buf) - 1, base_font->font_name.size);
236
	memcpy(buf, base_font->font_name.chars, l);
237
	buf[l] = 0;
238
	if (glyph_index >= 0)
239
	    eprintf2("Failed to interpret TT instructions of fhe glyph index %d of the font %s. "
240
			"Continue ignoring instructions of the font.\n", 
241
			glyph_index, buf);
242
	else
243
	    eprintf1("Failed to interpret TT instructions of the font %s. "
244
			"Continue ignoring instructions of the font.\n", 	    
245
			buf);
246
	base_font->data.warning_bad_instruction = true;
247
    }
248
}
249
 
250
private void WarnPatented(gs_font_type42 *pfont, ttfFont *ttf, const char *txt)
251
{
252
    if (!ttf->design_grid) {
253
	char buf[gs_font_name_max + 1];
254
	int l;
255
	gs_font_type42 *base_font = pfont;
256
 
257
	while ((gs_font_type42 *)base_font->base != base_font)
258
	    base_font = (gs_font_type42 *)base_font->base;
259
	if (!base_font->data.warning_patented) {
260
	    l = min(sizeof(buf) - 1, base_font->font_name.size);
261
	    memcpy(buf, base_font->font_name.chars, l);
262
	    buf[l] = 0;
263
	    eprintf2("%s %s requires a patented True Type interpreter.\n", txt, buf);
264
	    base_font->data.warning_patented = true;
265
	}
266
    }
267
}
268
 
269
/*----------------------------------------------*/
270
 
271
typedef struct gx_ttfMemory_s {
272
    ttfMemory super;
273
    gs_memory_t *memory;
274
} gx_ttfMemory;
275
 
276
gs_private_st_simple(st_gx_ttfMemory, gx_ttfMemory, "gx_ttfMemory");
277
/* st_gx_ttfMemory::memory points to a root. */
278
 
279
private void *gx_ttfMemory__alloc_bytes(ttfMemory *this, int size,  const char *cname)
280
{
281
    gs_memory_t *mem = ((gx_ttfMemory *)this)->memory;
282
 
283
    return gs_alloc_bytes(mem, size, cname);
284
}
285
 
286
private void *gx_ttfMemory__alloc_struct(ttfMemory *this, const ttfMemoryDescriptor *d,  const char *cname)
287
{
288
    gs_memory_t *mem = ((gx_ttfMemory *)this)->memory;
289
 
290
    return mem->procs.alloc_struct(mem, (const gs_memory_struct_type_t *)d, cname);
291
}
292
 
293
private void gx_ttfMemory__free(ttfMemory *this, void *p,  const char *cname)
294
{
295
    gs_memory_t *mem = ((gx_ttfMemory *)this)->memory;
296
 
297
    gs_free_object(mem, p, cname);
298
}
299
 
300
/*----------------------------------------------*/
301
 
302
static inline float reminder(float v, int x)
303
{
304
    return ((v / x) - floor(v / x)) * x;
305
}
306
 
307
private void decompose_matrix(const gs_font_type42 *pfont, const gs_matrix * char_tm, 
308
    const gs_log2_scale_point *log2_scale, bool design_grid,
309
    gs_point *char_size, gs_point *subpix_origin, gs_matrix *post_transform, bool *dg)
310
{
311
    /* 
312
     *	char_tm maps to subpixels. 
313
     */
314
    /*
315
     *	We use a Free Type 1 True Type interpreter, which cannot perform
316
     *	a grid-fitting with skewing/rotation. It appears acceptable
317
     *	because we want to minimize invocations of patented instructions.
318
     *	We believe that skewing/rotation requires the patented intrivial cases
319
     *	of projection/freedom vectors.
320
     */
321
    int scale_x = 1 << log2_scale->x;
322
    int scale_y = 1 << log2_scale->y;
323
    bool atp = gs_currentaligntopixels(pfont->dir);
324
    bool design_grid1;
325
 
326
    char_size->x = hypot(char_tm->xx, char_tm->xy);
327
    char_size->y = hypot(char_tm->yx, char_tm->yy);
328
    if (char_size->x <= 2 && char_size->y <= 2) {
329
    	/* Disable the grid fitting for very small fonts. */
330
	design_grid1 = true;
331
    } else
332
	design_grid1 = design_grid || !(gs_currentgridfittt(pfont->dir) & 1);
333
    *dg = design_grid1;
334
    subpix_origin->x = (atp ? 0 : reminder(char_tm->tx, scale_x) / scale_x);
335
    subpix_origin->y = (atp ? 0 : reminder(char_tm->ty, scale_y) / scale_y);
336
    post_transform->xx = char_tm->xx / (design_grid1 ? 1 : char_size->x);
337
    post_transform->xy = char_tm->xy / (design_grid1 ? 1 : char_size->x);
338
    post_transform->yx = char_tm->yx / (design_grid1 ? 1 : char_size->y);
339
    post_transform->yy = char_tm->yy / (design_grid1 ? 1 : char_size->y);
340
    post_transform->tx = char_tm->tx - subpix_origin->x;
341
    post_transform->ty = char_tm->ty - subpix_origin->y;
342
}
343
 
344
/*----------------------------------------------*/
345
 
346
ttfFont *ttfFont__create(gs_font_dir *dir)
347
{
348
    gs_memory_t *mem = dir->memory;
349
    gx_ttfMemory *m = gs_alloc_struct(mem, gx_ttfMemory, &st_gx_ttfMemory, "ttfFont__create");
350
    ttfFont *ttf;
351
 
352
    if (!m)
353
	return 0;
354
    m->super.alloc_struct = gx_ttfMemory__alloc_struct;
355
    m->super.alloc_bytes = gx_ttfMemory__alloc_bytes;
356
    m->super.free = gx_ttfMemory__free;
357
    m->memory = mem;
358
    if(ttfInterpreter__obtain(&m->super, &dir->tti))
359
	return 0;
360
    if(gx_san__obtain(mem->stable_memory, &dir->san))
361
	return 0;
362
    ttf = gs_alloc_struct(mem, ttfFont, &st_ttfFont, "ttfFont__create");
363
    if (ttf == NULL)
364
	return 0;
365
    ttfFont__init(ttf, &m->super, DebugRepaint, (gs_debug_c('Y') ? DebugPrint : NULL));
366
    return ttf;
367
}
368
 
369
void ttfFont__destroy(ttfFont *this, gs_font_dir *dir)
370
{   
371
    ttfMemory *mem = this->tti->ttf_memory;
372
 
373
    ttfFont__finit(this);
374
    mem->free(mem, this, "ttfFont__destroy");
375
    ttfInterpreter__release(&dir->tti);
376
    gx_san__release(&dir->san);
377
}
378
 
379
int ttfFont__Open_aux(ttfFont *this, ttfInterpreter *tti, gx_ttfReader *r, gs_font_type42 *pfont,
380
    	       const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
381
	       bool design_grid)
382
{
383
    gs_point char_size, subpix_origin;
384
    gs_matrix post_transform;
385
    /* 
386
     * Ghostscript proceses a TTC index in gs/lib/gs_ttf.ps, 
387
     * and *pfont already adjusted to it.
388
     * Therefore TTC headers never comes here. 
389
     */
390
    unsigned int nTTC = 0; 
391
    bool dg;
392
 
393
    decompose_matrix(pfont, char_tm, log2_scale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
394
    switch(ttfFont__Open(tti, this, &r->super, nTTC, char_size.x, char_size.y, dg)) {
395
	case fNoError:
396
	    return 0;
397
	case fMemoryError:
398
	    return_error(gs_error_VMerror);
399
	case fUnimplemented:
400
	    return_error(gs_error_unregistered);
401
	case fBadInstruction:
402
	    WarnBadInstruction(pfont, -1);
403
	    goto recover;
404
	case fPatented:
405
	    WarnPatented(pfont, this, "The font");
406
	recover:
407
	    this->patented = true;
408
	    return 0;
409
	default:
410
	    {	int code = r->super.Error(&r->super);
411
 
412
		if (code < 0)
413
		    return code;
414
		return_error(gs_error_invalidfont);
415
	    }
416
    }
417
}
418
 
419
/*----------------------------------------------*/
420
 
421
typedef struct gx_ttfExport_s {
422
    ttfExport super;
423
    gx_path *path;
424
    gs_fixed_point w;
425
    int error;
426
    bool monotonize;
427
} gx_ttfExport;
428
 
429
private void gx_ttfExport__MoveTo(ttfExport *this, FloatPoint *p)
430
{
431
    gx_ttfExport *e = (gx_ttfExport *)this;
432
 
433
    if (!e->error)
434
	e->error = gx_path_add_point(e->path, float2fixed(p->x), float2fixed(p->y));
435
}
436
 
437
private void gx_ttfExport__LineTo(ttfExport *this, FloatPoint *p)
438
{
439
    gx_ttfExport *e = (gx_ttfExport *)this;
440
 
441
    if (!e->error)
442
	e->error = gx_path_add_line_notes(e->path, float2fixed(p->x), float2fixed(p->y), sn_none);
443
}
444
 
445
private void gx_ttfExport__CurveTo(ttfExport *this, FloatPoint *p0, FloatPoint *p1, FloatPoint *p2)
446
{
447
    gx_ttfExport *e = (gx_ttfExport *)this;
448
 
449
    if (!e->error) {
450
	if (e->monotonize) {
451
	    curve_segment s;
452
 
453
	    s.notes = sn_none;
454
	    s.p1.x = float2fixed(p0->x), s.p1.y = float2fixed(p0->y), 
455
	    s.p2.x = float2fixed(p1->x), s.p2.y = float2fixed(p1->y), 
456
	    s.pt.x = float2fixed(p2->x), s.pt.y = float2fixed(p2->y);
457
	    e->error = gx_curve_monotonize(e->path, &s);
458
	} else
459
    	    e->error = gx_path_add_curve_notes(e->path, float2fixed(p0->x), float2fixed(p0->y), 
460
				     float2fixed(p1->x), float2fixed(p1->y), 
461
				     float2fixed(p2->x), float2fixed(p2->y), sn_none);
462
    }
463
}
464
 
465
private void gx_ttfExport__Close(ttfExport *this)
466
{
467
    gx_ttfExport *e = (gx_ttfExport *)this;
468
 
469
    if (!e->error)
470
	e->error = gx_path_close_subpath_notes(e->path, sn_none);
471
}
472
 
473
private void gx_ttfExport__Point(ttfExport *this, FloatPoint *p, bool bOnCurve, bool bNewPath)
474
{
475
    /* Never called. */
476
}
477
 
478
private void gx_ttfExport__SetWidth(ttfExport *this, FloatPoint *p)
479
{
480
    gx_ttfExport *e = (gx_ttfExport *)this;
481
 
482
    e->w.x = float2fixed(p->x); 
483
    e->w.y = float2fixed(p->y); 
484
}
485
 
486
private void gx_ttfExport__DebugPaint(ttfExport *this)
487
{
488
}
489
 
490
/*----------------------------------------------*/
491
 
492
private int
493
path_to_hinter(t1_hinter *h, gx_path *path)
494
{   int code;
495
    gs_path_enum penum;
496
    gs_fixed_point pts[3], p;
497
    bool first = true;
498
    int op;
499
 
500
    code = gx_path_enum_init(&penum, path);
501
    if (code < 0)
502
	return code;
503
    while ((op = gx_path_enum_next(&penum, pts)) != 0) {
504
	switch (op) {
505
	    case gs_pe_moveto:
506
		if (first) {
507
		    first = false;
508
		    p = pts[0];
509
		    code = t1_hinter__rmoveto(h, p.x, p.y);
510
		} else
511
		    code = t1_hinter__rmoveto(h, pts[0].x - p.x, pts[0].y - p.y);
512
		break;
513
	    case gs_pe_lineto:
514
		code = t1_hinter__rlineto(h, pts[0].x - p.x, pts[0].y - p.y);
515
		break;
516
	    case gs_pe_curveto:
517
		code = t1_hinter__rcurveto(h, pts[0].x - p.x, pts[0].y - p.y,
518
					pts[1].x - pts[0].x, pts[1].y - pts[0].y,
519
					pts[2].x - pts[1].x, pts[2].y - pts[1].y);
520
		pts[0] = pts[2];
521
		break;
522
	    case gs_pe_closepath:
523
		code = t1_hinter__closepath(h);
524
		break;
525
	    default:
526
		return_error(gs_error_unregistered);
527
	}
528
	if (code < 0)
529
	    return code;
530
	p = pts[0];
531
    }
532
    return 0;
533
}
534
 
535
#define exch(a,b) a^=b; b^=a; a^=b;
536
 
537
private void
538
transpose_path(gx_path *path)
539
{   segment *s = (segment *)path->first_subpath;
540
 
541
    exch(path->bbox.p.x, path->bbox.p.y);
542
    exch(path->bbox.q.x, path->bbox.q.y);
543
    for (; s; s = s->next) {
544
	if (s->type == s_curve) {
545
	    curve_segment *c = (curve_segment *)s;
546
 
547
	    exch(c->p1.x, c->p1.y);
548
	    exch(c->p2.x, c->p2.y);
549
	}
550
	exch(s->pt.x, s->pt.y);
551
    }
552
}
553
 
554
typedef struct {
555
    t1_hinter super;
556
    int transpose;
557
    fixed midx;
558
} t1_hinter_aux;
559
 
560
private int 
561
stem_hint_handler(void *client_data, gx_san_sect *ss)
562
{
563
    t1_hinter_aux *h = (t1_hinter_aux *)client_data;
564
 
565
    if (ss->side_mask == 3) {
566
	/* Orient horizontal hints to help with top/bottom alignment zones. 
567
	   Otherwize glyphs may get a random height due to serif adjustsment. */
568
	if (ss->xl > h->midx && h->transpose)
569
	    return (h->transpose ? t1_hinter__hstem : t1_hinter__vstem)
570
			(&h->super, ss->xr, ss->xl - ss->xr);
571
	else
572
	    return (h->transpose ? t1_hinter__hstem : t1_hinter__vstem)
573
			(&h->super, ss->xl, ss->xr - ss->xl);
574
    } else
575
	return t1_hinter__overall_hstem(&h->super, ss->xl, ss->xr - ss->xl, ss->side_mask);
576
}
577
 
578
#define OVERALL_HINT 0 /* Overall hints help to emulate Type 1 alignment zones
579
                          (except for overshoot suppression.)
580
			  For example, without it comparefiles/type42_glyph_index.ps
581
			  some glyphs have different height due to 
582
			  serifs are aligned in same way as horizontal stems,
583
			  but both sides of a stem have same priority.
584
 
585
			  This stuff appears low useful, because horizontal
586
			  hint orientation performs this job perfectly.
587
			  fixme : remove.
588
			  fixme : remove side_mask from gxhintn.c .
589
			  */
590
 
591
private int grid_fit(gx_device_spot_analyzer *padev, gx_path *path, 
592
	gs_font_type42 *pfont, const gs_log2_scale_point *pscale, gx_ttfExport *e, ttfOutliner *o)
593
{
594
    /* Not completed yet. */
595
    gs_imager_state is_stub;
596
    gx_fill_params params;
597
    gx_device_color devc_stub;
598
    int code;
599
    t1_hinter_aux h;
600
    gs_matrix m, fm, fmb;
601
    gs_matrix_fixed ctm_temp;
602
    bool atp = gs_currentaligntopixels(pfont->dir);
603
    int FontType = 1; /* Will apply Type 1 hinter. */
604
    fixed sbx = 0, sby = 0; /* stub */
605
    double scale = 1.0 / o->pFont->nUnitsPerEm;
606
    gs_fixed_rect bbox;
607
 
608
    m.xx = o->post_transform.a;
609
    m.xy = o->post_transform.b;
610
    m.yx = o->post_transform.c;
611
    m.yy = o->post_transform.d;
612
    m.tx = o->post_transform.tx;
613
    m.ty = o->post_transform.ty;
614
    code = gs_matrix_fixed_from_matrix(&ctm_temp, &m);
615
    if (code < 0)
616
	return code;
617
    code = gs_matrix_scale(&pfont->FontMatrix, scale, scale, &fm);
618
    if (code < 0)
619
	return code;
620
    code = gs_matrix_scale(&pfont->base->FontMatrix, scale, scale, &fmb);
621
    if (code < 0)
622
	return code;
623
    t1_hinter__init(&h.super, path); /* Will export to */
624
    code = t1_hinter__set_mapping(&h.super, &ctm_temp,
625
			&fm, &fmb,
626
			pscale->x, pscale->x, 0, 0,
627
			ctm_temp.tx_fixed, ctm_temp.ty_fixed, atp);
628
    if (code < 0)
629
	return code;
630
    if (!h.super.disable_hinting) {
631
	o->post_transform.a = o->post_transform.d = 1;
632
	o->post_transform.b = o->post_transform.c = 0;
633
	o->post_transform.tx = o->post_transform.ty = 0;
634
	ttfOutliner__DrawGlyphOutline(o);
635
	if (e->error)
636
	    return e->error;
637
	code = t1_hinter__set_font42_data(&h.super, FontType, &pfont->data, false);
638
	if (code < 0)
639
	    return code;
640
	code = t1_hinter__sbw(&h.super, sbx, sby, e->w.x, e->w.y);
641
	if (code < 0)
642
	    return code;
643
	gx_path_bbox(path, &bbox);
644
	if (code < 0)
645
	    return code;
646
	memset(&is_stub, 0, sizeof(is_stub));
647
	set_nonclient_dev_color(&devc_stub, 1);
648
	params.rule = gx_rule_winding_number;
649
	params.adjust.x = params.adjust.y = 0;
650
	params.flatness = fixed2float(max(bbox.q.x - bbox.p.x, bbox.q.y - bbox.p.y)) / 100.0;
651
	params.fill_zero_width = false;
652
 
653
	for (h.transpose = 0; h.transpose < 2; h.transpose++) {
654
	    h.midx = (padev->xmin + padev->xmax) / 2;
655
	    if (h.transpose)
656
		transpose_path(path);
657
	    gx_san_begin(padev);
658
	    code = dev_proc(padev, fill_path)((gx_device *)padev, 
659
			    &is_stub, path, &params, &devc_stub, NULL);
660
	    gx_san_end(padev);
661
	    if (code >= 0)
662
		code = gx_san_generate_stems(padev, OVERALL_HINT && h.transpose, 
663
				&h, stem_hint_handler);
664
	    if (h.transpose)
665
		transpose_path(path);
666
	    if (code < 0)
667
		return code;
668
	}
669
 
670
	/*  fixme : Storing hints permanently would be useful.
671
	    Note that if (gftt & 1), the outline and hints are already scaled.
672
	*/
673
	code = path_to_hinter(&h.super, path);
674
	if (code < 0)
675
	    return code;
676
	code = gx_path_new(path);
677
	if (code < 0)
678
	    return code;
679
	code = t1_hinter__endglyph(&h.super);
680
    } else {
681
	ttfOutliner__DrawGlyphOutline(o);
682
	if (e->error)
683
	    return e->error;
684
    }
685
    return code;
686
}
687
 
688
int gx_ttf_outline(ttfFont *ttf, gx_ttfReader *r, gs_font_type42 *pfont, int glyph_index, 
689
	const gs_matrix *m, const gs_log2_scale_point *pscale, 
690
	gx_path *path, bool design_grid)
691
{
692
    gx_ttfExport e;
693
    ttfOutliner o;
694
    gs_point char_size, subpix_origin;
695
    gs_matrix post_transform;
696
    /* Ghostscript proceses a TTC index in gs/lib/gs_ttf.ps, */
697
    /* so that TTC never comes here. */
698
    FloatMatrix m1;
699
    bool dg;
700
    uint gftt = gs_currentgridfittt(pfont->dir);
701
    bool ttin = (gftt & 1);
702
    /*	gs_currentgridfittt values (binary) :
703
	00 - no grid fitting;
704
	01 - Grid fit with TT interpreter; On failure warn and render unhinted.
705
	10 - Interpret in the design grid and then autohint.
706
	11 - Grid fit with TT interpreter; On failure render autohinted. 
707
    */
708
    bool auth = (gftt & 2);
709
 
710
    decompose_matrix(pfont, m, pscale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
711
    m1.a = post_transform.xx;
712
    m1.b = post_transform.xy;
713
    m1.c = post_transform.yx;
714
    m1.d = post_transform.yy;
715
    m1.tx = post_transform.tx;
716
    m1.ty = post_transform.ty;
717
    e.super.bPoints = false;
718
    e.super.bOutline = true;
719
    e.super.MoveTo = gx_ttfExport__MoveTo;
720
    e.super.LineTo = gx_ttfExport__LineTo;
721
    e.super.CurveTo = gx_ttfExport__CurveTo;
722
    e.super.Close = gx_ttfExport__Close;
723
    e.super.Point = gx_ttfExport__Point;
724
    e.super.SetWidth = gx_ttfExport__SetWidth;
725
    e.super.DebugPaint = gx_ttfExport__DebugPaint;
726
    e.error = 0;
727
    e.path = path;
728
    e.w.x = 0;
729
    e.w.y = 0;
730
    e.monotonize = auth;
731
    gx_ttfReader__Reset(r);
732
    ttfOutliner__init(&o, ttf, &r->super, &e.super, true, false, pfont->WMode != 0);
733
    switch(ttfOutliner__Outline(&o, glyph_index, subpix_origin.x, subpix_origin.y, &m1)) {
734
	case fBadInstruction:
735
	    WarnBadInstruction(pfont, glyph_index);
736
	    goto recover;
737
	case fPatented:
738
	    /* The returned outline did not apply a bytecode (it is not grid-fitted). */
739
	    if (!auth)
740
		WarnPatented(pfont, ttf, "Some glyphs of the font");
741
	recover :
742
	    if (!design_grid && auth)
743
		return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
744
	    /* Falls through. */
745
	case fNoError:
746
	    if (!design_grid && !ttin && auth)
747
		return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
748
	    ttfOutliner__DrawGlyphOutline(&o);
749
	    if (e.error)
750
		return e.error;
751
	    return 0;
752
	case fMemoryError:
753
	    return_error(gs_error_VMerror);
754
	case fUnimplemented:
755
	    return_error(gs_error_unregistered);
756
	default:
757
	    {	int code = r->super.Error(&r->super);
758
 
759
		if (code < 0)
760
		    return code;
761
		return_error(gs_error_invalidfont);
762
	    }
763
    }
764
}
765