2 |
- |
1 |
/* Copyright (C) 1989, 1995, 1996, 1997, 1998, 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: gsfont.c,v 1.37 2005/07/27 11:24:38 igor Exp $ */
|
|
|
18 |
/* Font operators for Ghostscript library */
|
|
|
19 |
#include "gx.h"
|
|
|
20 |
#include "memory_.h"
|
|
|
21 |
#include "gserrors.h"
|
|
|
22 |
#include "gsstruct.h"
|
|
|
23 |
#include "gsutil.h"
|
|
|
24 |
#include "gxfixed.h"
|
|
|
25 |
#include "gxmatrix.h"
|
|
|
26 |
#include "gzstate.h" /* must precede gxdevice */
|
|
|
27 |
#include "gxdevice.h" /* must precede gxfont */
|
|
|
28 |
#include "gxfont.h"
|
|
|
29 |
#include "gxfcache.h"
|
|
|
30 |
#include "gzpath.h" /* for default implementation */
|
|
|
31 |
|
|
|
32 |
/* Define the sizes of the various aspects of the font/character cache. */
|
|
|
33 |
/*** Big memory machines ***/
|
|
|
34 |
#define smax_LARGE 50 /* smax - # of scaled fonts */
|
|
|
35 |
#define bmax_LARGE 500000 /* bmax - space for cached chars */
|
|
|
36 |
#define mmax_LARGE 200 /* mmax - # of cached font/matrix pairs */
|
|
|
37 |
#define cmax_LARGE 5000 /* cmax - # of cached chars */
|
|
|
38 |
#define blimit_LARGE 2500 /* blimit/upper - max size of a single cached char */
|
|
|
39 |
/*** Small memory machines ***/
|
|
|
40 |
#define smax_SMALL 20 /* smax - # of scaled fonts */
|
|
|
41 |
#define bmax_SMALL 25000 /* bmax - space for cached chars */
|
|
|
42 |
#define mmax_SMALL 40 /* mmax - # of cached font/matrix pairs */
|
|
|
43 |
#define cmax_SMALL 500 /* cmax - # of cached chars */
|
|
|
44 |
#define blimit_SMALL 100 /* blimit/upper - max size of a single cached char */
|
|
|
45 |
|
|
|
46 |
/* Define a default procedure vector for fonts. */
|
|
|
47 |
const gs_font_procs gs_font_procs_default = {
|
|
|
48 |
gs_no_define_font, /* (actually a default) */
|
|
|
49 |
gs_no_make_font, /* (actually a default) */
|
|
|
50 |
gs_default_font_info,
|
|
|
51 |
gs_default_same_font,
|
|
|
52 |
gs_no_encode_char,
|
|
|
53 |
gs_no_decode_glyph,
|
|
|
54 |
gs_no_enumerate_glyph,
|
|
|
55 |
gs_default_glyph_info,
|
|
|
56 |
gs_no_glyph_outline,
|
|
|
57 |
gs_no_glyph_name,
|
|
|
58 |
gs_default_init_fstack,
|
|
|
59 |
gs_default_next_char_glyph,
|
|
|
60 |
gs_no_build_char
|
|
|
61 |
};
|
|
|
62 |
|
|
|
63 |
private_st_font_dir();
|
|
|
64 |
private struct_proc_enum_ptrs(font_enum_ptrs);
|
|
|
65 |
private struct_proc_reloc_ptrs(font_reloc_ptrs);
|
|
|
66 |
|
|
|
67 |
public_st_gs_font_info();
|
|
|
68 |
public_st_gs_font();
|
|
|
69 |
public_st_gs_font_base();
|
|
|
70 |
private_st_gs_font_ptr();
|
|
|
71 |
public_st_gs_font_ptr_element();
|
|
|
72 |
|
|
|
73 |
/*
|
|
|
74 |
* Garbage collection of fonts poses some special problems. On the one
|
|
|
75 |
* hand, we need to keep track of all existing base (not scaled) fonts,
|
|
|
76 |
* using the next/prev list whose head is the orig_fonts member of the font
|
|
|
77 |
* directory; on the other hand, we want these to be "weak" pointers that
|
|
|
78 |
* don't keep fonts in existence if the fonts aren't referenced from
|
|
|
79 |
* anywhere else. We accomplish this as follows:
|
|
|
80 |
*
|
|
|
81 |
* We don't trace through gs_font_dir.orig_fonts or gs_font.{next,prev}
|
|
|
82 |
* during the mark phase of the GC.
|
|
|
83 |
*
|
|
|
84 |
* When we finalize a base gs_font, we unlink it from the list. (A
|
|
|
85 |
* gs_font is a base font iff its base member points to itself.)
|
|
|
86 |
*
|
|
|
87 |
* We *do* relocate the orig_fonts and next/prev pointers during the
|
|
|
88 |
* relocation phase of the GC. */
|
|
|
89 |
|
|
|
90 |
/* Font directory GC procedures */
|
|
|
91 |
private
|
|
|
92 |
ENUM_PTRS_WITH(font_dir_enum_ptrs, gs_font_dir *dir)
|
|
|
93 |
{
|
|
|
94 |
/* Enumerate pointers from cached characters to f/m pairs, */
|
|
|
95 |
/* and mark the cached character glyphs. */
|
|
|
96 |
/* See gxfcache.h for why we do this here. */
|
|
|
97 |
uint cci = index - st_font_dir_max_ptrs;
|
|
|
98 |
uint offset, count;
|
|
|
99 |
uint tmask = dir->ccache.table_mask;
|
|
|
100 |
|
|
|
101 |
if (cci == 0)
|
|
|
102 |
offset = 0, count = 1;
|
|
|
103 |
else if (cci == dir->enum_index + 1)
|
|
|
104 |
offset = dir->enum_offset + 1, count = 1;
|
|
|
105 |
else
|
|
|
106 |
offset = 0, count = cci;
|
|
|
107 |
for (; offset <= tmask; ++offset) {
|
|
|
108 |
cached_char *cc = dir->ccache.table[offset];
|
|
|
109 |
|
|
|
110 |
if (cc != 0 && !--count) {
|
|
|
111 |
(*dir->ccache.mark_glyph)
|
|
|
112 |
(mem, cc->code, dir->ccache.mark_glyph_data);
|
|
|
113 |
/****** HACK: break const. We'll fix this someday. ******/
|
|
|
114 |
((gs_font_dir *)dir)->enum_index = cci;
|
|
|
115 |
((gs_font_dir *)dir)->enum_offset = offset;
|
|
|
116 |
ENUM_RETURN(cc_pair(cc) - cc->pair_index);
|
|
|
117 |
}
|
|
|
118 |
}
|
|
|
119 |
}
|
|
|
120 |
return 0;
|
|
|
121 |
#define e1(i,elt) ENUM_PTR(i,gs_font_dir,elt);
|
|
|
122 |
font_dir_do_ptrs(e1)
|
|
|
123 |
#undef e1
|
|
|
124 |
ENUM_PTRS_END
|
|
|
125 |
private RELOC_PTRS_WITH(font_dir_reloc_ptrs, gs_font_dir *dir);
|
|
|
126 |
/* Relocate the pointers from cached characters to f/m pairs. */
|
|
|
127 |
/* See gxfcache.h for why we do this here. */
|
|
|
128 |
{
|
|
|
129 |
int chi;
|
|
|
130 |
|
|
|
131 |
for (chi = dir->ccache.table_mask; chi >= 0; --chi) {
|
|
|
132 |
cached_char *cc = dir->ccache.table[chi];
|
|
|
133 |
|
|
|
134 |
if (cc != 0)
|
|
|
135 |
cc_set_pair_only(cc,
|
|
|
136 |
(cached_fm_pair *)
|
|
|
137 |
RELOC_OBJ(cc_pair(cc) - cc->pair_index) +
|
|
|
138 |
cc->pair_index);
|
|
|
139 |
}
|
|
|
140 |
}
|
|
|
141 |
/* We have to relocate the cached characters before we */
|
|
|
142 |
/* relocate dir->ccache.table! */
|
|
|
143 |
RELOC_PTR(gs_font_dir, orig_fonts);
|
|
|
144 |
#define r1(i,elt) RELOC_PTR(gs_font_dir, elt);
|
|
|
145 |
font_dir_do_ptrs(r1)
|
|
|
146 |
#undef r1
|
|
|
147 |
RELOC_PTRS_END
|
|
|
148 |
|
|
|
149 |
/* GC procedures for fonts */
|
|
|
150 |
/*
|
|
|
151 |
* When we finalize a base font, we unlink it from the orig_fonts list;
|
|
|
152 |
* when we finalize a scaled font, we unlink it from scaled_fonts.
|
|
|
153 |
* See above for more information.
|
|
|
154 |
*/
|
|
|
155 |
void
|
|
|
156 |
gs_font_finalize(void *vptr)
|
|
|
157 |
{
|
|
|
158 |
gs_font *const pfont = vptr;
|
|
|
159 |
gs_font **ppfirst;
|
|
|
160 |
gs_font *next = pfont->next;
|
|
|
161 |
gs_font *prev = pfont->prev;
|
|
|
162 |
|
|
|
163 |
if_debug4('u', "[u]unlinking font 0x%lx, base=0x%lx, prev=0x%lx, next=0x%lx\n",
|
|
|
164 |
(ulong) pfont, (ulong) pfont->base, (ulong) prev, (ulong) next);
|
|
|
165 |
/* Notify clients that the font is being freed. */
|
|
|
166 |
gs_notify_all(&pfont->notify_list, NULL);
|
|
|
167 |
if (pfont->dir == 0)
|
|
|
168 |
ppfirst = 0;
|
|
|
169 |
else if (pfont->base == pfont)
|
|
|
170 |
ppfirst = &pfont->dir->orig_fonts;
|
|
|
171 |
else {
|
|
|
172 |
/*
|
|
|
173 |
* Track the number of cached scaled fonts. Only decrement the
|
|
|
174 |
* count if we didn't do this already in gs_makefont.
|
|
|
175 |
*/
|
|
|
176 |
if (next || prev || pfont->dir->scaled_fonts == pfont)
|
|
|
177 |
pfont->dir->ssize--;
|
|
|
178 |
ppfirst = &pfont->dir->scaled_fonts;
|
|
|
179 |
}
|
|
|
180 |
/*
|
|
|
181 |
* gs_purge_font may have unlinked this font already:
|
|
|
182 |
* don't unlink it twice.
|
|
|
183 |
*/
|
|
|
184 |
if (next != 0 && next->prev == pfont)
|
|
|
185 |
next->prev = prev;
|
|
|
186 |
if (prev != 0) {
|
|
|
187 |
if (prev->next == pfont)
|
|
|
188 |
prev->next = next;
|
|
|
189 |
} else if (ppfirst != 0 && *ppfirst == pfont)
|
|
|
190 |
*ppfirst = next;
|
|
|
191 |
gs_notify_release(&pfont->notify_list);
|
|
|
192 |
}
|
|
|
193 |
private
|
|
|
194 |
ENUM_PTRS_WITH(font_enum_ptrs, gs_font *pfont) return ENUM_USING(st_gs_notify_list, &pfont->notify_list, sizeof(gs_notify_list_t), index - 5);
|
|
|
195 |
/* We don't enumerate next or prev of base fonts. */
|
|
|
196 |
/* See above for details. */
|
|
|
197 |
case 0: ENUM_RETURN((pfont->base == pfont ? 0 : pfont->next));
|
|
|
198 |
case 1: ENUM_RETURN((pfont->base == pfont ? 0 : pfont->prev));
|
|
|
199 |
ENUM_PTR3(2, gs_font, dir, base, client_data);
|
|
|
200 |
ENUM_PTRS_END
|
|
|
201 |
private RELOC_PTRS_WITH(font_reloc_ptrs, gs_font *pfont);
|
|
|
202 |
RELOC_USING(st_gs_notify_list, &pfont->notify_list, sizeof(gs_notify_list_t));
|
|
|
203 |
/* We *do* always relocate next and prev. */
|
|
|
204 |
/* Again, see above for details. */
|
|
|
205 |
RELOC_PTR(gs_font, next);
|
|
|
206 |
RELOC_PTR(gs_font, prev);
|
|
|
207 |
RELOC_PTR3(gs_font, dir, base, client_data);
|
|
|
208 |
RELOC_PTRS_END
|
|
|
209 |
|
|
|
210 |
/* Allocate a font directory */
|
|
|
211 |
private bool
|
|
|
212 |
cc_no_mark_glyph(const gs_memory_t *mem, gs_glyph glyph, void *ignore_data)
|
|
|
213 |
{
|
|
|
214 |
return false;
|
|
|
215 |
}
|
|
|
216 |
gs_font_dir *
|
|
|
217 |
gs_font_dir_alloc2(gs_memory_t * struct_mem, gs_memory_t * bits_mem)
|
|
|
218 |
{
|
|
|
219 |
gs_font_dir *pdir = 0;
|
|
|
220 |
|
|
|
221 |
#if !arch_small_memory
|
|
|
222 |
# ifdef DEBUG
|
|
|
223 |
if (!gs_debug_c('.'))
|
|
|
224 |
# endif
|
|
|
225 |
{ /* Try allocating a very large cache. */
|
|
|
226 |
/* If this fails, allocate a small one. */
|
|
|
227 |
pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
|
|
|
228 |
smax_LARGE, bmax_LARGE, mmax_LARGE,
|
|
|
229 |
cmax_LARGE, blimit_LARGE);
|
|
|
230 |
}
|
|
|
231 |
if (pdir == 0)
|
|
|
232 |
#endif
|
|
|
233 |
pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
|
|
|
234 |
smax_SMALL, bmax_SMALL, mmax_SMALL,
|
|
|
235 |
cmax_SMALL, blimit_SMALL);
|
|
|
236 |
if (pdir == 0)
|
|
|
237 |
return 0;
|
|
|
238 |
pdir->ccache.mark_glyph = cc_no_mark_glyph;
|
|
|
239 |
pdir->ccache.mark_glyph_data = 0;
|
|
|
240 |
return pdir;
|
|
|
241 |
}
|
|
|
242 |
gs_font_dir *
|
|
|
243 |
gs_font_dir_alloc2_limits(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
|
|
|
244 |
uint smax, uint bmax, uint mmax, uint cmax, uint upper)
|
|
|
245 |
{
|
|
|
246 |
gs_font_dir *pdir =
|
|
|
247 |
gs_alloc_struct(struct_mem, gs_font_dir, &st_font_dir,
|
|
|
248 |
"font_dir_alloc(dir)");
|
|
|
249 |
int code;
|
|
|
250 |
|
|
|
251 |
if (pdir == 0)
|
|
|
252 |
return 0;
|
|
|
253 |
code = gx_char_cache_alloc(struct_mem, bits_mem, pdir,
|
|
|
254 |
bmax, mmax, cmax, upper);
|
|
|
255 |
if (code < 0) {
|
|
|
256 |
gs_free_object(struct_mem, pdir, "font_dir_alloc(dir)");
|
|
|
257 |
return 0;
|
|
|
258 |
}
|
|
|
259 |
pdir->orig_fonts = 0;
|
|
|
260 |
pdir->scaled_fonts = 0;
|
|
|
261 |
pdir->ssize = 0;
|
|
|
262 |
pdir->smax = smax;
|
|
|
263 |
pdir->align_to_pixels = false;
|
|
|
264 |
pdir->glyph_to_unicode_table = NULL;
|
|
|
265 |
pdir->grid_fit_tt = 2;
|
|
|
266 |
pdir->memory = struct_mem;
|
|
|
267 |
pdir->tti = 0;
|
|
|
268 |
pdir->san = 0;
|
|
|
269 |
pdir->global_glyph_code = NULL;
|
|
|
270 |
return pdir;
|
|
|
271 |
}
|
|
|
272 |
|
|
|
273 |
/* Allocate and minimally initialize a font. */
|
|
|
274 |
gs_font *
|
|
|
275 |
gs_font_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
|
|
|
276 |
const gs_font_procs *procs, gs_font_dir *dir,
|
|
|
277 |
client_name_t cname)
|
|
|
278 |
{
|
|
|
279 |
gs_font *pfont = gs_alloc_struct(mem, gs_font, pstype, cname);
|
|
|
280 |
|
|
|
281 |
if (pfont == 0)
|
|
|
282 |
return 0;
|
|
|
283 |
#if 1 /* Clear entire structure to avoid unitialized pointers
|
|
|
284 |
when the initialization exits prematurely by error. */
|
|
|
285 |
memset(pfont, 0, pstype->ssize);
|
|
|
286 |
pfont->memory = mem;
|
|
|
287 |
pfont->dir = dir;
|
|
|
288 |
gs_font_notify_init(pfont);
|
|
|
289 |
pfont->id = gs_next_ids(mem, 1);
|
|
|
290 |
pfont->base = pfont;
|
|
|
291 |
pfont->ExactSize = pfont->InBetweenSize = pfont->TransformedChar =
|
|
|
292 |
fbit_use_outlines;
|
|
|
293 |
pfont->procs = *procs;
|
|
|
294 |
#else
|
|
|
295 |
/* For clarity we leave old initializations here
|
|
|
296 |
to know which fields needs to be initialized. */
|
|
|
297 |
pfont->next = pfont->prev = 0;
|
|
|
298 |
pfont->memory = mem;
|
|
|
299 |
pfont->dir = dir;
|
|
|
300 |
pfont->is_resource = false;
|
|
|
301 |
gs_font_notify_init(pfont);
|
|
|
302 |
pfont->id = gs_next_ids(mem, 1);
|
|
|
303 |
pfont->base = pfont;
|
|
|
304 |
pfont->client_data = 0;
|
|
|
305 |
/* not FontMatrix, FontType */
|
|
|
306 |
pfont->BitmapWidths = false;
|
|
|
307 |
pfont->ExactSize = pfont->InBetweenSize = pfont->TransformedChar =
|
|
|
308 |
fbit_use_outlines;
|
|
|
309 |
pfont->WMode = 0;
|
|
|
310 |
pfont->PaintType = 0;
|
|
|
311 |
pfont->StrokeWidth = 0;
|
|
|
312 |
pfont->procs = *procs;
|
|
|
313 |
memset(&pfont->orig_FontMatrix, 0, sizeof(pfont->orig_FontMatrix));
|
|
|
314 |
#endif
|
|
|
315 |
/* not key_name, font_name */
|
|
|
316 |
return pfont;
|
|
|
317 |
}
|
|
|
318 |
/* Allocate and minimally initialize a base font. */
|
|
|
319 |
gs_font_base *
|
|
|
320 |
gs_font_base_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
|
|
|
321 |
const gs_font_procs *procs, gs_font_dir *dir,
|
|
|
322 |
client_name_t cname)
|
|
|
323 |
{
|
|
|
324 |
gs_font_base *pfont =
|
|
|
325 |
(gs_font_base *)gs_font_alloc(mem, pstype, procs, dir, cname);
|
|
|
326 |
|
|
|
327 |
if (pfont == 0)
|
|
|
328 |
return 0;
|
|
|
329 |
pfont->FontBBox.p.x = pfont->FontBBox.p.y =
|
|
|
330 |
pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0;
|
|
|
331 |
uid_set_invalid(&pfont->UID);
|
|
|
332 |
pfont->encoding_index = pfont->nearest_encoding_index = -1;
|
|
|
333 |
return pfont;
|
|
|
334 |
}
|
|
|
335 |
|
|
|
336 |
/* Initialize the notification list for a font. */
|
|
|
337 |
void
|
|
|
338 |
gs_font_notify_init(gs_font *font)
|
|
|
339 |
{
|
|
|
340 |
/*
|
|
|
341 |
* The notification list for a font must be allocated in the font's
|
|
|
342 |
* stable memory, because of the following possible sequence of events:
|
|
|
343 |
*
|
|
|
344 |
* - Allocate font X in local VM.
|
|
|
345 |
* - Client A registers for notification when X is freed.
|
|
|
346 |
* - 'save'
|
|
|
347 |
* - Client B registers for notification when X is freed.
|
|
|
348 |
* - 'restore'
|
|
|
349 |
*
|
|
|
350 |
* If the notification list element for client B is allocated in
|
|
|
351 |
* restorable local VM (i.e., the same VM as the font), then when the
|
|
|
352 |
* 'restore' occurs, either the list element will be deleted (not what
|
|
|
353 |
* client B wants, because font X hasn't been freed yet), or there will
|
|
|
354 |
* be a dangling pointer.
|
|
|
355 |
*/
|
|
|
356 |
gs_notify_init(&font->notify_list, gs_memory_stable(font->memory));
|
|
|
357 |
}
|
|
|
358 |
|
|
|
359 |
|
|
|
360 |
/*
|
|
|
361 |
* Register/unregister a client for notification by a font. Currently
|
|
|
362 |
* the clients are only notified when a font is freed. Note that any
|
|
|
363 |
* such client must unregister itself when *it* is freed.
|
|
|
364 |
*/
|
|
|
365 |
int
|
|
|
366 |
gs_font_notify_register(gs_font *font, gs_notify_proc_t proc, void *proc_data)
|
|
|
367 |
{
|
|
|
368 |
return gs_notify_register(&font->notify_list, proc, proc_data);
|
|
|
369 |
}
|
|
|
370 |
int
|
|
|
371 |
gs_font_notify_unregister(gs_font *font, gs_notify_proc_t proc, void *proc_data)
|
|
|
372 |
{
|
|
|
373 |
return gs_notify_unregister(&font->notify_list, proc, proc_data);
|
|
|
374 |
}
|
|
|
375 |
|
|
|
376 |
/* Link an element at the head of a chain. */
|
|
|
377 |
private void
|
|
|
378 |
font_link_first(gs_font **pfirst, gs_font *elt)
|
|
|
379 |
{
|
|
|
380 |
gs_font *first = elt->next = *pfirst;
|
|
|
381 |
|
|
|
382 |
if (first)
|
|
|
383 |
first->prev = elt;
|
|
|
384 |
elt->prev = 0;
|
|
|
385 |
*pfirst = elt;
|
|
|
386 |
}
|
|
|
387 |
|
|
|
388 |
/* definefont */
|
|
|
389 |
/* Use this only for original (unscaled) fonts! */
|
|
|
390 |
/* Note that it expects pfont->procs.define_font to be set already. */
|
|
|
391 |
int
|
|
|
392 |
gs_definefont(gs_font_dir * pdir, gs_font * pfont)
|
|
|
393 |
{
|
|
|
394 |
int code;
|
|
|
395 |
|
|
|
396 |
pfont->dir = pdir;
|
|
|
397 |
pfont->base = pfont;
|
|
|
398 |
code = (*pfont->procs.define_font) (pdir, pfont);
|
|
|
399 |
if (code < 0) { /* Make sure we don't try to finalize this font. */
|
|
|
400 |
pfont->base = 0;
|
|
|
401 |
return code;
|
|
|
402 |
}
|
|
|
403 |
font_link_first(&pdir->orig_fonts, pfont);
|
|
|
404 |
if_debug2('m', "[m]defining font 0x%lx, next=0x%lx\n",
|
|
|
405 |
(ulong) pfont, (ulong) pfont->next);
|
|
|
406 |
return 0;
|
|
|
407 |
}
|
|
|
408 |
|
|
|
409 |
/* Find a sililar registered font of same type. */
|
|
|
410 |
int
|
|
|
411 |
gs_font_find_similar(const gs_font_dir * pdir, const gs_font **ppfont,
|
|
|
412 |
int (*similar)(const gs_font *, const gs_font *))
|
|
|
413 |
{
|
|
|
414 |
const gs_font *pfont0 = *ppfont;
|
|
|
415 |
const gs_font *pfont1 = pdir->orig_fonts;
|
|
|
416 |
|
|
|
417 |
for (; pfont1 != NULL; pfont1 = pfont1->next) {
|
|
|
418 |
if (pfont1 != pfont0 && pfont1->FontType == pfont0->FontType) {
|
|
|
419 |
int code = similar(pfont0, pfont1);
|
|
|
420 |
if (code != 0) {
|
|
|
421 |
*ppfont = pfont1;
|
|
|
422 |
return code;
|
|
|
423 |
}
|
|
|
424 |
}
|
|
|
425 |
}
|
|
|
426 |
return 0;
|
|
|
427 |
}
|
|
|
428 |
|
|
|
429 |
/* scalefont */
|
|
|
430 |
int
|
|
|
431 |
gs_scalefont(gs_font_dir * pdir, const gs_font * pfont, floatp scale,
|
|
|
432 |
gs_font ** ppfont)
|
|
|
433 |
{
|
|
|
434 |
gs_matrix mat;
|
|
|
435 |
|
|
|
436 |
gs_make_scaling(scale, scale, &mat);
|
|
|
437 |
return gs_makefont(pdir, pfont, &mat, ppfont);
|
|
|
438 |
}
|
|
|
439 |
|
|
|
440 |
/* makefont */
|
|
|
441 |
int
|
|
|
442 |
gs_makefont(gs_font_dir * pdir, const gs_font * pfont,
|
|
|
443 |
const gs_matrix * pmat, gs_font ** ppfont)
|
|
|
444 |
{
|
|
|
445 |
int code;
|
|
|
446 |
gs_font *prev = 0;
|
|
|
447 |
gs_font *pf_out = pdir->scaled_fonts;
|
|
|
448 |
gs_memory_t *mem = pfont->memory;
|
|
|
449 |
gs_matrix newmat;
|
|
|
450 |
bool can_cache;
|
|
|
451 |
|
|
|
452 |
if ((code = gs_matrix_multiply(&pfont->FontMatrix, pmat, &newmat)) < 0)
|
|
|
453 |
return code;
|
|
|
454 |
/*
|
|
|
455 |
* Check for the font already being in the scaled font cache.
|
|
|
456 |
* Until version 5.97, we only cached scaled fonts if the base
|
|
|
457 |
* (unscaled) font had a valid UniqueID or XUID; now, we will cache
|
|
|
458 |
* scaled versions of any non-composite font.
|
|
|
459 |
*/
|
|
|
460 |
#ifdef DEBUG
|
|
|
461 |
if (gs_debug_c('m')) {
|
|
|
462 |
const gs_font_base *const pbfont = (const gs_font_base *)pfont;
|
|
|
463 |
|
|
|
464 |
if (pfont->FontType == ft_composite)
|
|
|
465 |
dlprintf("[m]composite");
|
|
|
466 |
else if (uid_is_UniqueID(&pbfont->UID))
|
|
|
467 |
dlprintf1("[m]UniqueID=%ld", pbfont->UID.id);
|
|
|
468 |
else if (uid_is_XUID(&pbfont->UID))
|
|
|
469 |
dlprintf1("[m]XUID(%u)", (uint) (-pbfont->UID.id));
|
|
|
470 |
else
|
|
|
471 |
dlprintf("[m]no UID");
|
|
|
472 |
dprintf7(", FontType=%d,\n[m] new FontMatrix=[%g %g %g %g %g %g]\n",
|
|
|
473 |
pfont->FontType,
|
|
|
474 |
pmat->xx, pmat->xy, pmat->yx, pmat->yy,
|
|
|
475 |
pmat->tx, pmat->ty);
|
|
|
476 |
}
|
|
|
477 |
#endif
|
|
|
478 |
/*
|
|
|
479 |
* Don't try to cache scaled composite fonts, because of the side
|
|
|
480 |
* effects on FDepVector and descendant fonts that occur in makefont.
|
|
|
481 |
*/
|
|
|
482 |
if (pfont->FontType != ft_composite) {
|
|
|
483 |
for (; pf_out != 0; prev = pf_out, pf_out = pf_out->next)
|
|
|
484 |
if (pf_out->FontType == pfont->FontType &&
|
|
|
485 |
pf_out->base == pfont->base &&
|
|
|
486 |
pf_out->FontMatrix.xx == newmat.xx &&
|
|
|
487 |
pf_out->FontMatrix.xy == newmat.xy &&
|
|
|
488 |
pf_out->FontMatrix.yx == newmat.yx &&
|
|
|
489 |
pf_out->FontMatrix.yy == newmat.yy &&
|
|
|
490 |
pf_out->FontMatrix.tx == newmat.tx &&
|
|
|
491 |
pf_out->FontMatrix.ty == newmat.ty
|
|
|
492 |
) {
|
|
|
493 |
*ppfont = pf_out;
|
|
|
494 |
if_debug1('m', "[m]found font=0x%lx\n", (ulong) pf_out);
|
|
|
495 |
return 0;
|
|
|
496 |
}
|
|
|
497 |
can_cache = true;
|
|
|
498 |
} else
|
|
|
499 |
can_cache = false;
|
|
|
500 |
pf_out = gs_alloc_struct(mem, gs_font, gs_object_type(mem, pfont),
|
|
|
501 |
"gs_makefont");
|
|
|
502 |
if (!pf_out)
|
|
|
503 |
return_error(gs_error_VMerror);
|
|
|
504 |
memcpy(pf_out, pfont, gs_object_size(mem, pfont));
|
|
|
505 |
gs_font_notify_init(pf_out);
|
|
|
506 |
pf_out->FontMatrix = newmat;
|
|
|
507 |
pf_out->client_data = 0;
|
|
|
508 |
pf_out->dir = pdir;
|
|
|
509 |
pf_out->base = pfont->base;
|
|
|
510 |
*ppfont = pf_out;
|
|
|
511 |
code = (*pf_out->procs.make_font) (pdir, pfont, pmat, ppfont);
|
|
|
512 |
if (code < 0)
|
|
|
513 |
return code;
|
|
|
514 |
if (can_cache) {
|
|
|
515 |
if (pdir->ssize >= pdir->smax && prev != 0) {
|
|
|
516 |
/*
|
|
|
517 |
* We must discard a cached scaled font.
|
|
|
518 |
* prev points to the last (oldest) font.
|
|
|
519 |
* (We can't free it, because there might be
|
|
|
520 |
* other references to it.)
|
|
|
521 |
*/
|
|
|
522 |
if_debug1('m', "[m]discarding font 0x%lx\n",
|
|
|
523 |
(ulong) prev);
|
|
|
524 |
if (prev->prev != 0)
|
|
|
525 |
prev->prev->next = 0;
|
|
|
526 |
else
|
|
|
527 |
pdir->scaled_fonts = 0;
|
|
|
528 |
pdir->ssize--;
|
|
|
529 |
prev->prev = 0;
|
|
|
530 |
if (prev->FontType != ft_composite) {
|
|
|
531 |
if_debug1('m', "[m]discarding UID 0x%lx\n",
|
|
|
532 |
(ulong) ((gs_font_base *) prev)->
|
|
|
533 |
UID.xvalues);
|
|
|
534 |
uid_free(&((gs_font_base *) prev)->UID,
|
|
|
535 |
prev->memory,
|
|
|
536 |
"gs_makefont(discarding)");
|
|
|
537 |
uid_set_invalid(&((gs_font_base *) prev)->UID);
|
|
|
538 |
}
|
|
|
539 |
}
|
|
|
540 |
pdir->ssize++;
|
|
|
541 |
font_link_first(&pdir->scaled_fonts, pf_out);
|
|
|
542 |
} else { /* Prevent garbage pointers. */
|
|
|
543 |
pf_out->next = pf_out->prev = 0;
|
|
|
544 |
}
|
|
|
545 |
if_debug2('m', "[m]new font=0x%lx can_cache=%s\n",
|
|
|
546 |
(ulong) * ppfont, (can_cache ? "true" : "false"));
|
|
|
547 |
return 1;
|
|
|
548 |
}
|
|
|
549 |
|
|
|
550 |
/* Set the current font. This is provided only for the benefit of cshow, */
|
|
|
551 |
/* which must reset the current font without disturbing the root font. */
|
|
|
552 |
void
|
|
|
553 |
gs_set_currentfont(gs_state * pgs, gs_font * pfont)
|
|
|
554 |
{
|
|
|
555 |
pgs->font = pfont;
|
|
|
556 |
pgs->char_tm_valid = false;
|
|
|
557 |
}
|
|
|
558 |
|
|
|
559 |
/* setfont */
|
|
|
560 |
int
|
|
|
561 |
gs_setfont(gs_state * pgs, gs_font * pfont)
|
|
|
562 |
{
|
|
|
563 |
pgs->font = pgs->root_font = pfont;
|
|
|
564 |
pgs->char_tm_valid = false;
|
|
|
565 |
return 0;
|
|
|
566 |
}
|
|
|
567 |
|
|
|
568 |
/* currentfont */
|
|
|
569 |
gs_font *
|
|
|
570 |
gs_currentfont(const gs_state * pgs)
|
|
|
571 |
{
|
|
|
572 |
return pgs->font;
|
|
|
573 |
}
|
|
|
574 |
|
|
|
575 |
/* rootfont */
|
|
|
576 |
gs_font *
|
|
|
577 |
gs_rootfont(const gs_state * pgs)
|
|
|
578 |
{
|
|
|
579 |
return pgs->root_font;
|
|
|
580 |
}
|
|
|
581 |
|
|
|
582 |
/* cachestatus */
|
|
|
583 |
void
|
|
|
584 |
gs_cachestatus(register const gs_font_dir * pdir, register uint pstat[7])
|
|
|
585 |
{
|
|
|
586 |
pstat[0] = pdir->ccache.bsize;
|
|
|
587 |
pstat[1] = pdir->ccache.bmax;
|
|
|
588 |
pstat[2] = pdir->fmcache.msize;
|
|
|
589 |
pstat[3] = pdir->fmcache.mmax;
|
|
|
590 |
pstat[4] = pdir->ccache.csize;
|
|
|
591 |
pstat[5] = pdir->ccache.cmax;
|
|
|
592 |
pstat[6] = pdir->ccache.upper;
|
|
|
593 |
}
|
|
|
594 |
|
|
|
595 |
/* setcacheparams */
|
|
|
596 |
int
|
|
|
597 |
gs_setcachesize(gs_font_dir * pdir, uint size)
|
|
|
598 |
{ /* This doesn't delete anything from the cache yet. */
|
|
|
599 |
pdir->ccache.bmax = size;
|
|
|
600 |
return 0;
|
|
|
601 |
}
|
|
|
602 |
int
|
|
|
603 |
gs_setcachelower(gs_font_dir * pdir, uint size)
|
|
|
604 |
{
|
|
|
605 |
pdir->ccache.lower = size;
|
|
|
606 |
return 0;
|
|
|
607 |
}
|
|
|
608 |
int
|
|
|
609 |
gs_setcacheupper(gs_font_dir * pdir, uint size)
|
|
|
610 |
{
|
|
|
611 |
pdir->ccache.upper = size;
|
|
|
612 |
return 0;
|
|
|
613 |
}
|
|
|
614 |
int
|
|
|
615 |
gs_setaligntopixels(gs_font_dir * pdir, uint v)
|
|
|
616 |
{
|
|
|
617 |
pdir->align_to_pixels = v;
|
|
|
618 |
return 0;
|
|
|
619 |
}
|
|
|
620 |
int
|
|
|
621 |
gs_setgridfittt(gs_font_dir * pdir, uint v)
|
|
|
622 |
{
|
|
|
623 |
pdir->grid_fit_tt = v;
|
|
|
624 |
return 0;
|
|
|
625 |
}
|
|
|
626 |
|
|
|
627 |
/* currentcacheparams */
|
|
|
628 |
uint
|
|
|
629 |
gs_currentcachesize(const gs_font_dir * pdir)
|
|
|
630 |
{
|
|
|
631 |
return pdir->ccache.bmax;
|
|
|
632 |
}
|
|
|
633 |
uint
|
|
|
634 |
gs_currentcachelower(const gs_font_dir * pdir)
|
|
|
635 |
{
|
|
|
636 |
return pdir->ccache.lower;
|
|
|
637 |
}
|
|
|
638 |
uint
|
|
|
639 |
gs_currentcacheupper(const gs_font_dir * pdir)
|
|
|
640 |
{
|
|
|
641 |
return pdir->ccache.upper;
|
|
|
642 |
}
|
|
|
643 |
uint
|
|
|
644 |
gs_currentaligntopixels(const gs_font_dir * pdir)
|
|
|
645 |
{
|
|
|
646 |
return pdir->align_to_pixels;
|
|
|
647 |
}
|
|
|
648 |
uint
|
|
|
649 |
gs_currentgridfittt(const gs_font_dir * pdir)
|
|
|
650 |
{
|
|
|
651 |
return pdir->grid_fit_tt;
|
|
|
652 |
}
|
|
|
653 |
|
|
|
654 |
/* Purge a font from all font- and character-related tables. */
|
|
|
655 |
/* This is only used by restore (and, someday, the GC). */
|
|
|
656 |
void
|
|
|
657 |
gs_purge_font(gs_font * pfont)
|
|
|
658 |
{
|
|
|
659 |
gs_font_dir *pdir = pfont->dir;
|
|
|
660 |
gs_font *pf;
|
|
|
661 |
|
|
|
662 |
/* Remove the font from its list (orig_fonts or scaled_fonts). */
|
|
|
663 |
gs_font *prev = pfont->prev;
|
|
|
664 |
gs_font *next = pfont->next;
|
|
|
665 |
|
|
|
666 |
if (next != 0)
|
|
|
667 |
next->prev = prev, pfont->next = 0;
|
|
|
668 |
if (prev != 0)
|
|
|
669 |
prev->next = next, pfont->prev = 0;
|
|
|
670 |
else if (pdir->orig_fonts == pfont)
|
|
|
671 |
pdir->orig_fonts = next;
|
|
|
672 |
else if (pdir->scaled_fonts == pfont)
|
|
|
673 |
pdir->scaled_fonts = next;
|
|
|
674 |
else { /* Shouldn't happen! */
|
|
|
675 |
lprintf1("purged font 0x%lx not found\n", (ulong) pfont);
|
|
|
676 |
}
|
|
|
677 |
|
|
|
678 |
/* Purge the font from the scaled font cache. */
|
|
|
679 |
for (pf = pdir->scaled_fonts; pf != 0;) {
|
|
|
680 |
if (pf->base == pfont) {
|
|
|
681 |
gs_purge_font(pf);
|
|
|
682 |
pf = pdir->scaled_fonts; /* start over */
|
|
|
683 |
} else
|
|
|
684 |
pf = pf->next;
|
|
|
685 |
}
|
|
|
686 |
|
|
|
687 |
/* Purge the font from the font/matrix pair cache, */
|
|
|
688 |
/* including all cached characters rendered with that font. */
|
|
|
689 |
gs_purge_font_from_char_caches(pdir, pfont);
|
|
|
690 |
|
|
|
691 |
}
|
|
|
692 |
|
|
|
693 |
/* Locate a gs_font by gs_id. */
|
|
|
694 |
gs_font *
|
|
|
695 |
gs_find_font_by_id(gs_font_dir *pdir, gs_id id, gs_matrix *FontMatrix)
|
|
|
696 |
{
|
|
|
697 |
gs_font *pfont = pdir->orig_fonts;
|
|
|
698 |
|
|
|
699 |
for(; pfont != NULL; pfont = pfont->next)
|
|
|
700 |
if(pfont->id == id &&
|
|
|
701 |
!memcmp(&pfont->FontMatrix, FontMatrix, sizeof(pfont->FontMatrix)))
|
|
|
702 |
return pfont;
|
|
|
703 |
return NULL;
|
|
|
704 |
}
|
|
|
705 |
|
|
|
706 |
/* ---------------- Default font procedures ---------------- */
|
|
|
707 |
|
|
|
708 |
/* ------ Font-level procedures ------ */
|
|
|
709 |
|
|
|
710 |
/* Default (vacuous) definefont handler. */
|
|
|
711 |
int
|
|
|
712 |
gs_no_define_font(gs_font_dir * pdir, gs_font * pfont)
|
|
|
713 |
{
|
|
|
714 |
return 0;
|
|
|
715 |
}
|
|
|
716 |
|
|
|
717 |
/* Default (vacuous) makefont handler. */
|
|
|
718 |
int
|
|
|
719 |
gs_no_make_font(gs_font_dir * pdir, const gs_font * pfont,
|
|
|
720 |
const gs_matrix * pmat, gs_font ** ppfont)
|
|
|
721 |
{
|
|
|
722 |
return 0;
|
|
|
723 |
}
|
|
|
724 |
/* Makefont handler for base fonts, which must copy the XUID. */
|
|
|
725 |
int
|
|
|
726 |
gs_base_make_font(gs_font_dir * pdir, const gs_font * pfont,
|
|
|
727 |
const gs_matrix * pmat, gs_font ** ppfont)
|
|
|
728 |
{
|
|
|
729 |
return uid_copy(&((gs_font_base *)*ppfont)->UID, (*ppfont)->memory,
|
|
|
730 |
"gs_base_make_font(XUID)");
|
|
|
731 |
}
|
|
|
732 |
|
|
|
733 |
/* Default font info procedure */
|
|
|
734 |
int
|
|
|
735 |
gs_default_font_info(gs_font *font, const gs_point *pscale, int members,
|
|
|
736 |
gs_font_info_t *info)
|
|
|
737 |
{
|
|
|
738 |
int wmode = font->WMode;
|
|
|
739 |
gs_font_base *bfont = (gs_font_base *)font;
|
|
|
740 |
gs_point scale;
|
|
|
741 |
gs_matrix smat;
|
|
|
742 |
const gs_matrix *pmat;
|
|
|
743 |
|
|
|
744 |
if (pscale == 0) {
|
|
|
745 |
scale.x = scale.y = 0;
|
|
|
746 |
pmat = 0;
|
|
|
747 |
} else {
|
|
|
748 |
scale = *pscale;
|
|
|
749 |
gs_make_scaling(scale.x, scale.y, &smat);
|
|
|
750 |
pmat = &smat;
|
|
|
751 |
}
|
|
|
752 |
info->members = 0;
|
|
|
753 |
if (members & FONT_INFO_FLAGS)
|
|
|
754 |
info->Flags_returned = 0;
|
|
|
755 |
if (font->FontType == ft_composite)
|
|
|
756 |
return 0; /* nothing available */
|
|
|
757 |
if (members & FONT_INFO_BBOX) {
|
|
|
758 |
info->BBox.p.x = (int)bfont->FontBBox.p.x;
|
|
|
759 |
info->BBox.p.y = (int)bfont->FontBBox.p.y;
|
|
|
760 |
info->BBox.q.x = (int)bfont->FontBBox.q.x;
|
|
|
761 |
info->BBox.q.y = (int)bfont->FontBBox.q.y;
|
|
|
762 |
info->Flags_returned |= FONT_INFO_BBOX;
|
|
|
763 |
}
|
|
|
764 |
if ((members & FONT_INFO_FLAGS) &&
|
|
|
765 |
(info->Flags_requested & FONT_IS_FIXED_WIDTH)
|
|
|
766 |
) {
|
|
|
767 |
/*
|
|
|
768 |
* Scan the glyph space to compute the fixed width if any.
|
|
|
769 |
*/
|
|
|
770 |
gs_glyph notdef = gs_no_glyph;
|
|
|
771 |
gs_glyph glyph;
|
|
|
772 |
int fixed_width = 0;
|
|
|
773 |
int index;
|
|
|
774 |
int code = 0; /* Quiet compiler. */
|
|
|
775 |
|
|
|
776 |
for (index = 0;
|
|
|
777 |
fixed_width >= 0 &&
|
|
|
778 |
(code = font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_NAME, &glyph)) >= 0 &&
|
|
|
779 |
index != 0;
|
|
|
780 |
) {
|
|
|
781 |
gs_glyph_info_t glyph_info;
|
|
|
782 |
|
|
|
783 |
code = font->procs.glyph_info(font, glyph, pmat,
|
|
|
784 |
(GLYPH_INFO_WIDTH0 << wmode),
|
|
|
785 |
&glyph_info);
|
|
|
786 |
if (code < 0)
|
|
|
787 |
return code;
|
|
|
788 |
if (notdef == gs_no_glyph && gs_font_glyph_is_notdef(bfont, glyph)) {
|
|
|
789 |
notdef = glyph;
|
|
|
790 |
info->MissingWidth = (int)glyph_info.width[wmode].x;
|
|
|
791 |
info->members |= FONT_INFO_MISSING_WIDTH;
|
|
|
792 |
}
|
|
|
793 |
if (glyph_info.width[wmode].y != 0)
|
|
|
794 |
fixed_width = min_int;
|
|
|
795 |
else if (fixed_width == 0)
|
|
|
796 |
fixed_width = (int)glyph_info.width[wmode].x;
|
|
|
797 |
else if (glyph_info.width[wmode].x != fixed_width)
|
|
|
798 |
fixed_width = min_int;
|
|
|
799 |
}
|
|
|
800 |
if (code < 0)
|
|
|
801 |
return code;
|
|
|
802 |
if (fixed_width > 0) {
|
|
|
803 |
info->Flags |= FONT_IS_FIXED_WIDTH;
|
|
|
804 |
info->members |= FONT_INFO_AVG_WIDTH | FONT_INFO_MAX_WIDTH |
|
|
|
805 |
FONT_INFO_MISSING_WIDTH;
|
|
|
806 |
info->AvgWidth = info->MaxWidth = info->MissingWidth = fixed_width;
|
|
|
807 |
}
|
|
|
808 |
info->Flags_returned |= FONT_IS_FIXED_WIDTH;
|
|
|
809 |
} else if (members & FONT_INFO_MISSING_WIDTH) {
|
|
|
810 |
gs_glyph glyph;
|
|
|
811 |
int index;
|
|
|
812 |
|
|
|
813 |
for (index = 0;
|
|
|
814 |
font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_NAME, &glyph) >= 0 &&
|
|
|
815 |
index != 0;
|
|
|
816 |
) {
|
|
|
817 |
/*
|
|
|
818 |
* If this is a CIDFont or TrueType font that uses integers as
|
|
|
819 |
* glyph names, check for glyph 0; otherwise, check for .notdef.
|
|
|
820 |
*/
|
|
|
821 |
if (!gs_font_glyph_is_notdef(bfont, glyph))
|
|
|
822 |
continue;
|
|
|
823 |
{
|
|
|
824 |
gs_glyph_info_t glyph_info;
|
|
|
825 |
int code = font->procs.glyph_info(font, glyph, pmat,
|
|
|
826 |
(GLYPH_INFO_WIDTH0 << wmode),
|
|
|
827 |
&glyph_info);
|
|
|
828 |
|
|
|
829 |
if (code < 0)
|
|
|
830 |
return code;
|
|
|
831 |
info->MissingWidth = (int)glyph_info.width[wmode].x;
|
|
|
832 |
info->members |= FONT_INFO_MISSING_WIDTH;
|
|
|
833 |
break;
|
|
|
834 |
}
|
|
|
835 |
}
|
|
|
836 |
}
|
|
|
837 |
return 0;
|
|
|
838 |
}
|
|
|
839 |
|
|
|
840 |
/* Default font similarity testing procedure */
|
|
|
841 |
int
|
|
|
842 |
gs_default_same_font(const gs_font *font, const gs_font *ofont, int mask)
|
|
|
843 |
{
|
|
|
844 |
while (font->base != font)
|
|
|
845 |
font = font->base;
|
|
|
846 |
while (ofont->base != ofont)
|
|
|
847 |
ofont = ofont->base;
|
|
|
848 |
if (ofont == font)
|
|
|
849 |
return mask;
|
|
|
850 |
/* In general, we can't determine similarity. */
|
|
|
851 |
return 0;
|
|
|
852 |
}
|
|
|
853 |
int
|
|
|
854 |
gs_base_same_font(const gs_font *font, const gs_font *ofont, int mask)
|
|
|
855 |
{
|
|
|
856 |
int same = gs_default_same_font(font, ofont, mask);
|
|
|
857 |
|
|
|
858 |
if (!same) {
|
|
|
859 |
const gs_font_base *const bfont = (const gs_font_base *)font;
|
|
|
860 |
const gs_font_base *const obfont = (const gs_font_base *)ofont;
|
|
|
861 |
|
|
|
862 |
if (mask & FONT_SAME_ENCODING) {
|
|
|
863 |
if (bfont->encoding_index != ENCODING_INDEX_UNKNOWN ||
|
|
|
864 |
obfont->encoding_index != ENCODING_INDEX_UNKNOWN
|
|
|
865 |
) {
|
|
|
866 |
if (bfont->encoding_index == obfont->encoding_index)
|
|
|
867 |
same |= FONT_SAME_ENCODING;
|
|
|
868 |
}
|
|
|
869 |
}
|
|
|
870 |
}
|
|
|
871 |
return same;
|
|
|
872 |
}
|
|
|
873 |
|
|
|
874 |
/* ------ Glyph-level procedures ------ */
|
|
|
875 |
|
|
|
876 |
/*
|
|
|
877 |
* Test whether a glyph is the notdef glyph for a base font.
|
|
|
878 |
* The test is somewhat adhoc: perhaps this should be a virtual procedure.
|
|
|
879 |
*/
|
|
|
880 |
bool
|
|
|
881 |
gs_font_glyph_is_notdef(gs_font_base *bfont, gs_glyph glyph)
|
|
|
882 |
{
|
|
|
883 |
gs_const_string gnstr;
|
|
|
884 |
|
|
|
885 |
if (glyph == gs_no_glyph)
|
|
|
886 |
return false;
|
|
|
887 |
if (glyph >= gs_min_cid_glyph)
|
|
|
888 |
return (glyph == gs_min_cid_glyph);
|
|
|
889 |
return (bfont->procs.glyph_name((gs_font *)bfont, glyph, &gnstr) >= 0 &&
|
|
|
890 |
gnstr.size == 7 && !memcmp(gnstr.data, ".notdef", 7));
|
|
|
891 |
}
|
|
|
892 |
|
|
|
893 |
/* Dummy character encoding procedure */
|
|
|
894 |
gs_glyph
|
|
|
895 |
gs_no_encode_char(gs_font *pfont, gs_char chr, gs_glyph_space_t glyph_space)
|
|
|
896 |
{
|
|
|
897 |
return gs_no_glyph;
|
|
|
898 |
}
|
|
|
899 |
|
|
|
900 |
/* Dummy glyph decoding procedure */
|
|
|
901 |
gs_char
|
|
|
902 |
gs_no_decode_glyph(gs_font *pfont, gs_glyph glyph)
|
|
|
903 |
{
|
|
|
904 |
return GS_NO_CHAR;
|
|
|
905 |
}
|
|
|
906 |
|
|
|
907 |
/* Dummy glyph enumeration procedure */
|
|
|
908 |
int
|
|
|
909 |
gs_no_enumerate_glyph(gs_font *font, int *pindex, gs_glyph_space_t glyph_space,
|
|
|
910 |
gs_glyph *pglyph)
|
|
|
911 |
{
|
|
|
912 |
return_error(gs_error_undefined);
|
|
|
913 |
}
|
|
|
914 |
|
|
|
915 |
/* Default glyph info procedure */
|
|
|
916 |
int
|
|
|
917 |
gs_default_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
|
|
|
918 |
int members, gs_glyph_info_t *info)
|
|
|
919 |
{ /* WMode may be inherited from an upper font. */
|
|
|
920 |
gx_path path;
|
|
|
921 |
int returned = 0;
|
|
|
922 |
int code;
|
|
|
923 |
int wmode = ((members & GLYPH_INFO_WIDTH1) != 0);
|
|
|
924 |
double sbw[4] = {0, 0, 0, 0};
|
|
|
925 |
/* Currently glyph_outline retrieves sbw only with type 1,2,9 fonts. */
|
|
|
926 |
bool charstrings_font = (font->FontType == ft_encrypted ||
|
|
|
927 |
font->FontType == ft_encrypted2 ||
|
|
|
928 |
font->FontType == ft_CID_encrypted);
|
|
|
929 |
|
|
|
930 |
gx_path_init_bbox_accumulator(&path);
|
|
|
931 |
code = gx_path_add_point(&path, fixed_0, fixed_0);
|
|
|
932 |
if (code < 0)
|
|
|
933 |
goto out;
|
|
|
934 |
code = font->procs.glyph_outline(font, wmode, glyph, pmat, &path, sbw);
|
|
|
935 |
if (code < 0)
|
|
|
936 |
goto out;
|
|
|
937 |
if (members & GLYPH_INFO_WIDTHS) {
|
|
|
938 |
int wmode = font->WMode;
|
|
|
939 |
int wmask = GLYPH_INFO_WIDTH0 << wmode;
|
|
|
940 |
|
|
|
941 |
if (members & wmask) {
|
|
|
942 |
gs_fixed_point pt;
|
|
|
943 |
|
|
|
944 |
code = gx_path_current_point(&path, &pt);
|
|
|
945 |
if (code < 0)
|
|
|
946 |
goto out;
|
|
|
947 |
info->width[wmode].x = fixed2float(pt.x);
|
|
|
948 |
info->width[wmode].y = fixed2float(pt.y);
|
|
|
949 |
returned |= wmask;
|
|
|
950 |
}
|
|
|
951 |
}
|
|
|
952 |
if (members & GLYPH_INFO_BBOX) {
|
|
|
953 |
gs_fixed_rect bbox;
|
|
|
954 |
|
|
|
955 |
code = gx_path_bbox(&path, &bbox);
|
|
|
956 |
if (code < 0)
|
|
|
957 |
goto out;
|
|
|
958 |
info->bbox.p.x = fixed2float(bbox.p.x);
|
|
|
959 |
info->bbox.p.y = fixed2float(bbox.p.y);
|
|
|
960 |
info->bbox.q.x = fixed2float(bbox.q.x);
|
|
|
961 |
info->bbox.q.y = fixed2float(bbox.q.y);
|
|
|
962 |
returned |= GLYPH_INFO_BBOX;
|
|
|
963 |
}
|
|
|
964 |
if (members & (GLYPH_INFO_WIDTH0 << wmode) && charstrings_font) {
|
|
|
965 |
if (pmat == 0) {
|
|
|
966 |
info->width[wmode].x = sbw[2];
|
|
|
967 |
info->width[wmode].y = sbw[3];
|
|
|
968 |
} else {
|
|
|
969 |
code = gs_distance_transform(sbw[2], sbw[3], pmat, &info->width[wmode]);
|
|
|
970 |
if (code < 0)
|
|
|
971 |
return code;
|
|
|
972 |
}
|
|
|
973 |
returned |= GLYPH_INFO_WIDTH0 << wmode;
|
|
|
974 |
}
|
|
|
975 |
if (members & (GLYPH_INFO_VVECTOR0 << wmode) && charstrings_font) {
|
|
|
976 |
if (pmat == 0) {
|
|
|
977 |
info->v.x = sbw[0];
|
|
|
978 |
info->v.y = sbw[1];
|
|
|
979 |
} else {
|
|
|
980 |
gs_distance_transform(sbw[0], sbw[1], pmat, &info->v);
|
|
|
981 |
if (code < 0)
|
|
|
982 |
return code;
|
|
|
983 |
}
|
|
|
984 |
returned |= GLYPH_INFO_VVECTOR0 << wmode;
|
|
|
985 |
}
|
|
|
986 |
if (members & GLYPH_INFO_NUM_PIECES) {
|
|
|
987 |
info->num_pieces = 0;
|
|
|
988 |
returned |= GLYPH_INFO_NUM_PIECES;
|
|
|
989 |
}
|
|
|
990 |
returned |= members & GLYPH_INFO_PIECES; /* no pieces stored */
|
|
|
991 |
out:
|
|
|
992 |
info->members = returned;
|
|
|
993 |
return code;
|
|
|
994 |
}
|
|
|
995 |
|
|
|
996 |
/* Dummy glyph outline procedure */
|
|
|
997 |
int
|
|
|
998 |
gs_no_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat,
|
|
|
999 |
gx_path *ppath, double sbw[4])
|
|
|
1000 |
{
|
|
|
1001 |
return_error(gs_error_undefined);
|
|
|
1002 |
}
|
|
|
1003 |
|
|
|
1004 |
/* Dummy glyph name procedure */
|
|
|
1005 |
int
|
|
|
1006 |
gs_no_glyph_name(gs_font *font, gs_glyph glyph, gs_const_string *pstr)
|
|
|
1007 |
{
|
|
|
1008 |
return_error(gs_error_undefined);
|
|
|
1009 |
}
|
|
|
1010 |
|