xref: /plan9/sys/src/cmd/gs/src/gxttfb.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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
ENUM_PTRS_WITH(gx_ttfReader_enum_ptrs,gx_ttfReader * mptr)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 
gx_ttfReader__Eof(ttfReader * this)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 
gx_ttfReader__Read(ttfReader * this,void * p,int n)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 
gx_ttfReader__Seek(ttfReader * this,int nPos)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 
gx_ttfReader__Tell(ttfReader * this)108 private int gx_ttfReader__Tell(ttfReader *this)
109 {
110     gx_ttfReader *r = (gx_ttfReader *)this;
111 
112     return r->pos;
113 }
114 
gx_ttfReader__Error(ttfReader * this)115 private bool gx_ttfReader__Error(ttfReader *this)
116 {
117     gx_ttfReader *r = (gx_ttfReader *)this;
118 
119     return r->error;
120 }
121 
gx_ttfReader__LoadGlyph(ttfReader * this,int glyph_index,const byte ** p,int * size)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 
gx_ttfReader__ReleaseGlyph(ttfReader * this,int glyph_index)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 
gx_ttfReader__Reset(gx_ttfReader * this)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 
gx_ttfReader__create(gs_memory_t * mem)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 
gx_ttfReader__destroy(gx_ttfReader * this)192 void gx_ttfReader__destroy(gx_ttfReader *this)
193 {
194     gs_free_object(this->memory, this, "gx_ttfReader__destroy");
195 }
196 
gx_ttfReader__set_font(gx_ttfReader * this,gs_font_type42 * pfont)197 void gx_ttfReader__set_font(gx_ttfReader *this, gs_font_type42 *pfont)
198 {
199     this->pfont = pfont;
200 }
201 
202 
203 /*----------------------------------------------*/
204 
DebugRepaint(ttfFont * ttf)205 private void DebugRepaint(ttfFont *ttf)
206 {
207 }
208 
DebugPrint(ttfFont * ttf,const char * fmt,...)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 
WarnBadInstruction(gs_font_type42 * pfont,int glyph_index)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 
WarnPatented(gs_font_type42 * pfont,ttfFont * ttf,const char * txt)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 
gx_ttfMemory__alloc_bytes(ttfMemory * this,int size,const char * cname)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 
gx_ttfMemory__alloc_struct(ttfMemory * this,const ttfMemoryDescriptor * d,const char * cname)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 
gx_ttfMemory__free(ttfMemory * this,void * p,const char * cname)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 
reminder(float v,int x)302 static inline float reminder(float v, int x)
303 {
304     return ((v / x) - floor(v / x)) * x;
305 }
306 
decompose_matrix(const gs_font_type42 * pfont,const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,bool design_grid,gs_point * char_size,gs_point * subpix_origin,gs_matrix * post_transform,bool * dg)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 
ttfFont__create(gs_font_dir * dir)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 
ttfFont__destroy(ttfFont * this,gs_font_dir * dir)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 
ttfFont__Open_aux(ttfFont * this,ttfInterpreter * tti,gx_ttfReader * r,gs_font_type42 * pfont,const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,bool design_grid)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 
gx_ttfExport__MoveTo(ttfExport * this,FloatPoint * p)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 
gx_ttfExport__LineTo(ttfExport * this,FloatPoint * p)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 
gx_ttfExport__CurveTo(ttfExport * this,FloatPoint * p0,FloatPoint * p1,FloatPoint * p2)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 
gx_ttfExport__Close(ttfExport * this)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 
gx_ttfExport__Point(ttfExport * this,FloatPoint * p,bool bOnCurve,bool bNewPath)473 private void gx_ttfExport__Point(ttfExport *this, FloatPoint *p, bool bOnCurve, bool bNewPath)
474 {
475     /* Never called. */
476 }
477 
gx_ttfExport__SetWidth(ttfExport * this,FloatPoint * p)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 
gx_ttfExport__DebugPaint(ttfExport * this)486 private void gx_ttfExport__DebugPaint(ttfExport *this)
487 {
488 }
489 
490 /*----------------------------------------------*/
491 
492 private int
path_to_hinter(t1_hinter * h,gx_path * path)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
transpose_path(gx_path * path)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
stem_hint_handler(void * client_data,gx_san_sect * ss)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 
grid_fit(gx_device_spot_analyzer * padev,gx_path * path,gs_font_type42 * pfont,const gs_log2_scale_point * pscale,gx_ttfExport * e,ttfOutliner * o)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 
gx_ttf_outline(ttfFont * ttf,gx_ttfReader * r,gs_font_type42 * pfont,int glyph_index,const gs_matrix * m,const gs_log2_scale_point * pscale,gx_path * path,bool design_grid)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 
766