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, ¶ms, &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