Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gsfont.c
Line
Count
Source
1
/* Copyright (C) 2001-2024 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Font operators for Ghostscript library */
18
#include "gx.h"
19
#include "memory_.h"
20
#include "gserrors.h"
21
#include "gsstruct.h"
22
#include "gsutil.h"
23
#include "gxfixed.h"
24
#include "gxmatrix.h"
25
#include "gzstate.h"    /* must precede gxdevice */
26
#include "gxdevice.h"   /* must precede gxfont */
27
#include "gxfont.h"
28
#include "gxfcache.h"
29
#include "gzpath.h"   /* for default implementation */
30
31
/* Define the sizes of the various aspects of the font/character cache. */
32
/*** Big memory machines ***/
33
282k
#define smax_LARGE 50    /* smax - # of scaled fonts */
34
282k
#define bmax_LARGE 1000000  /* bmax - space for cached chars */
35
282k
#define mmax_LARGE 200    /* mmax - # of cached font/matrix pairs */
36
282k
#define cmax_LARGE 5000    /* cmax - # of cached chars */
37
282k
#define blimit_LARGE 32000  /* blimit/upper - max size of a single cached char */
38
/*** Small memory machines ***/
39
0
#define smax_SMALL 20    /* smax - # of scaled fonts */
40
0
#define bmax_SMALL 25000  /* bmax - space for cached chars */
41
0
#define mmax_SMALL 40    /* mmax - # of cached font/matrix pairs */
42
0
#define cmax_SMALL 500    /* cmax - # of cached chars */
43
0
#define blimit_SMALL 100  /* blimit/upper - max size of a single cached char */
44
45
/* Define a default procedure vector for fonts. */
46
const gs_font_procs gs_font_procs_default = {
47
    gs_no_define_font,    /* (actually a default) */
48
    gs_no_make_font,    /* (actually a default) */
49
    gs_default_font_info,
50
    gs_default_same_font,
51
    gs_no_encode_char,
52
    gs_no_decode_glyph,
53
    gs_no_enumerate_glyph,
54
    gs_default_glyph_info,
55
    gs_no_glyph_outline,
56
    gs_no_glyph_name,
57
    gs_default_init_fstack,
58
    gs_default_next_char_glyph,
59
    gs_no_build_char
60
};
61
62
private_st_font_dir();
63
static struct_proc_enum_ptrs(font_enum_ptrs);
64
static struct_proc_reloc_ptrs(font_reloc_ptrs);
65
66
public_st_gs_font_info();
67
public_st_gs_font();
68
public_st_gs_font_base();
69
private_st_gs_font_ptr();
70
public_st_gs_font_ptr_element();
71
72
/*
73
 * Garbage collection of fonts poses some special problems.  On the one
74
 * hand, we need to keep track of all existing base (not scaled) fonts,
75
 * using the next/prev list whose head is the orig_fonts member of the font
76
 * directory; on the other hand, we want these to be "weak" pointers that
77
 * don't keep fonts in existence if the fonts aren't referenced from
78
 * anywhere else.  We accomplish this as follows:
79
 *
80
 *     We don't trace through gs_font_dir.orig_fonts or gs_font.{next,prev}
81
 * during the mark phase of the GC.
82
 *
83
 *     When we finalize a base gs_font, we unlink it from the list.  (A
84
 * gs_font is a base font iff its base member points to itself.)
85
 *
86
 *     We *do* relocate the orig_fonts and next/prev pointers during the
87
 * relocation phase of the GC.  */
88
89
/* Font directory GC procedures */
90
static
91
7.69M
ENUM_PTRS_WITH(font_dir_enum_ptrs, gs_font_dir *dir)
92
1.24M
{
93
    /* Enumerate pointers from cached characters to f/m pairs, */
94
    /* and mark the cached character glyphs. */
95
    /* See gxfcache.h for why we do this here. */
96
1.24M
    uint cci = index - st_font_dir_max_ptrs;
97
1.24M
    uint offset, count;
98
1.24M
    uint tmask = dir->ccache.table_mask;
99
100
1.24M
    if (cci == 0)
101
807k
        offset = 0, count = 1;
102
434k
    else if (cci == dir->enum_index + 1)
103
434k
        offset = dir->enum_offset + 1, count = 1;
104
0
    else
105
0
        offset = 0, count = cci;
106
13.2G
    for (; offset <= tmask; ++offset) {
107
13.2G
        cached_char *cc = dir->ccache.table[offset];
108
109
13.2G
        if (cc != 0 && !--count) {
110
434k
            (*dir->ccache.mark_glyph)
111
434k
                (mem, cc->code, dir->ccache.mark_glyph_data);
112
            /****** HACK: break const.  We'll fix this someday. ******/
113
434k
            ((gs_font_dir *)dir)->enum_index = cci;
114
434k
            ((gs_font_dir *)dir)->enum_offset = offset;
115
434k
            ENUM_RETURN(cc_pair(cc) - cc->pair_index);
116
434k
        }
117
13.2G
    }
118
1.24M
}
119
807k
return 0;
120
6.45M
#define e1(i,elt) ENUM_PTR(i,gs_font_dir,elt);
121
7.69M
font_dir_do_ptrs(e1)
122
7.69M
#undef e1
123
7.69M
ENUM_PTRS_END
124
448k
static RELOC_PTRS_WITH(font_dir_reloc_ptrs, gs_font_dir *dir);
125
    /* Relocate the pointers from cached characters to f/m pairs. */
126
    /* See gxfcache.h for why we do this here. */
127
448k
{
128
448k
    int chi;
129
130
7.34G
    for (chi = dir->ccache.table_mask; chi >= 0; --chi) {
131
7.34G
        cached_char *cc = dir->ccache.table[chi];
132
133
7.34G
        if (cc != 0)
134
217k
            cc_set_pair_only(cc,
135
7.34G
                             (cached_fm_pair *)
136
7.34G
                             RELOC_OBJ(cc_pair(cc) - cc->pair_index) +
137
7.34G
                             cc->pair_index);
138
7.34G
    }
139
448k
}
140
    /* We have to relocate the cached characters before we */
141
    /* relocate dir->ccache.table! */
142
448k
RELOC_PTR(gs_font_dir, orig_fonts);
143
3.58M
#define r1(i,elt) RELOC_PTR(gs_font_dir, elt);
144
3.58M
font_dir_do_ptrs(r1)
145
448k
#undef r1
146
448k
RELOC_PTRS_END
147
148
/* GC procedures for fonts */
149
/*
150
 * When we finalize a base font, we unlink it from the orig_fonts list;
151
 * when we finalize a scaled font, we unlink it from scaled_fonts.
152
 * See above for more information.
153
 */
154
void
155
gs_font_finalize(const gs_memory_t *cmem, void *vptr)
156
3.00M
{
157
3.00M
    gs_font *const pfont = vptr;
158
3.00M
    gs_font **ppfirst;
159
3.00M
    gs_font *next = pfont->next;
160
3.00M
    gs_font *prev = pfont->prev;
161
3.00M
    (void)cmem; /* unused */
162
163
3.00M
    if_debug4m('u', cmem, "[u]unlinking font "PRI_INTPTR", base="PRI_INTPTR", prev="PRI_INTPTR", next="PRI_INTPTR"\n",
164
3.00M
               (intptr_t)pfont, (intptr_t)pfont->base, (intptr_t)prev, (intptr_t)next);
165
    /* Notify clients that the font is being freed. */
166
3.00M
    gs_notify_all(&pfont->notify_list, NULL);
167
3.00M
    gs_purge_font_from_char_caches(pfont);
168
3.00M
    if (pfont->dir == 0)
169
0
        ppfirst = 0;
170
3.00M
    else if (pfont->base == pfont)
171
2.98M
        ppfirst = &pfont->dir->orig_fonts;
172
19.5k
    else {
173
        /*
174
         * Track the number of cached scaled fonts.  Only decrement the
175
         * count if we didn't do this already in gs_makefont.
176
         */
177
19.5k
        if (next || prev || pfont->dir->scaled_fonts == pfont)
178
17.2k
            pfont->dir->ssize--;
179
19.5k
        ppfirst = &pfont->dir->scaled_fonts;
180
19.5k
    }
181
    /*
182
     * gs_purge_font may have unlinked this font already:
183
     * don't unlink it twice.
184
     */
185
3.00M
    if (next != 0 && next->prev == pfont)
186
615k
        next->prev = prev;
187
3.00M
    if (prev != 0) {
188
404k
        if (prev->next == pfont)
189
404k
            prev->next = next;
190
2.60M
    } else if (ppfirst != 0 && *ppfirst == pfont)
191
296k
        *ppfirst = next;
192
193
3.00M
    if (pfont->FontType != ft_composite) {
194
2.99M
        gs_font_base *pbfont = (gs_font_base *)pfont;
195
2.99M
        if (uid_is_XUID(&pbfont->UID)) {
196
68.3k
            uid_free(&pbfont->UID, pbfont->memory, "gs_font_finalize");
197
68.3k
        }
198
2.99M
    }
199
200
3.00M
    gs_notify_release(&pfont->notify_list);
201
3.00M
}
202
static
203
3.73M
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);
204
        /* We don't enumerate next or prev of base fonts. */
205
        /* See above for details. */
206
533k
case 0: ENUM_RETURN((pfont->base == pfont ? 0 : pfont->next));
207
533k
case 1: ENUM_RETURN((pfont->base == pfont ? 0 : pfont->prev));
208
3.73M
ENUM_PTR3(2, gs_font, dir, base, client_data);
209
3.73M
ENUM_PTRS_END
210
533k
static RELOC_PTRS_WITH(font_reloc_ptrs, gs_font *pfont);
211
533k
RELOC_USING(st_gs_notify_list, &pfont->notify_list, sizeof(gs_notify_list_t));
212
        /* We *do* always relocate next and prev. */
213
        /* Again, see above for details. */
214
533k
RELOC_PTR(gs_font, next);
215
533k
RELOC_PTR(gs_font, prev);
216
533k
RELOC_PTR3(gs_font, dir, base, client_data);
217
533k
RELOC_PTRS_END
218
219
/* Allocate a font directory */
220
static bool
221
cc_no_mark_glyph(const gs_memory_t *mem, gs_glyph glyph, void *ignore_data)
222
0
{
223
0
    return false;
224
0
}
225
gs_font_dir *
226
gs_font_dir_alloc2(gs_memory_t * struct_mem, gs_memory_t * bits_mem)
227
282k
{
228
282k
    gs_font_dir *pdir = 0;
229
230
282k
#if !ARCH_SMALL_MEMORY
231
#  ifdef DEBUG
232
    if (!gs_debug_c('.'))
233
#  endif
234
282k
    {       /* Try allocating a very large cache. */
235
        /* If this fails, allocate a small one. */
236
282k
        pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
237
282k
                                         smax_LARGE, bmax_LARGE, mmax_LARGE,
238
282k
                                         cmax_LARGE, blimit_LARGE);
239
282k
    }
240
282k
    if (pdir == 0)
241
0
#endif
242
0
        pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
243
0
                                         smax_SMALL, bmax_SMALL, mmax_SMALL,
244
0
                                         cmax_SMALL, blimit_SMALL);
245
282k
    if (pdir == NULL)
246
0
        return NULL;
247
282k
    pdir->ccache.mark_glyph = cc_no_mark_glyph;
248
282k
    pdir->ccache.mark_glyph_data = 0;
249
282k
    return pdir;
250
282k
}
251
gs_font_dir *
252
gs_font_dir_alloc2_limits(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
253
                     uint smax, uint bmax, uint mmax, uint cmax, uint upper)
254
374k
{
255
374k
    gs_font_dir *pdir =
256
374k
        gs_alloc_struct(struct_mem, gs_font_dir, &st_font_dir,
257
374k
                        "font_dir_alloc(dir)");
258
374k
    int code;
259
260
374k
    if (pdir == NULL)
261
0
        return NULL;
262
374k
    memset(pdir, 0, sizeof(*pdir));
263
374k
    pdir->memory = struct_mem;
264
374k
    code = gx_char_cache_alloc(struct_mem, bits_mem, pdir,
265
374k
                               bmax, mmax, cmax, upper);
266
374k
    if (code < 0) {
267
0
        gs_free_object(struct_mem, pdir, "font_dir_alloc(dir)");
268
0
        return NULL;
269
0
    }
270
374k
    pdir->orig_fonts = 0;
271
374k
    pdir->scaled_fonts = 0;
272
374k
    pdir->ssize = 0;
273
374k
    pdir->smax = smax;
274
374k
    pdir->align_to_pixels = false;
275
374k
    pdir->glyph_to_unicode_table = NULL;
276
374k
    pdir->grid_fit_tt = 1;
277
374k
    pdir->tti = 0;
278
374k
    pdir->ttm = 0;
279
374k
    pdir->san = 0;
280
374k
    pdir->global_glyph_code = NULL;
281
374k
    pdir->text_enum_id = 0;
282
374k
    pdir->hash = 42;  /* initialize the hash to a randomly picked number */
283
374k
    return pdir;
284
374k
}
285
static void
286
gs_font_dir_finalize(const gs_memory_t *cmem, void *vptr)
287
374k
{
288
374k
    gs_font_dir *pdir = vptr;
289
374k
    gx_bits_cache_chunk *chunk = pdir->ccache.chunks;
290
374k
    gx_bits_cache_chunk *start_chunk = chunk;
291
374k
    gx_bits_cache_chunk *prev_chunk;
292
374k
    int i;
293
294
374k
    if (pdir == cmem->gs_lib_ctx->font_dir) {
295
174k
        cmem->gs_lib_ctx->font_dir = NULL;
296
174k
    }
297
298
75.2M
    for (i = 0; i < pdir->fmcache.mmax; i++) {
299
74.8M
        if (uid_is_XUID(&pdir->fmcache.mdata[i].UID)) {
300
58.9k
            gs_free_object(pdir->memory->stable_memory, pdir->fmcache.mdata[i].UID.xvalues, "gs_font_dir_finalize");
301
58.9k
        }
302
74.8M
    }
303
304
    /* free character cache machinery */
305
374k
    gs_free_object(pdir->memory, pdir->fmcache.mdata, "gs_font_dir_finalize");
306
374k
    gs_free_object(pdir->memory, pdir->ccache.table, "gs_font_dir_finalize");
307
308
    /* free the circular list of memory chunks */
309
414k
    while (chunk) {
310
414k
        if (start_chunk == chunk->next) {
311
374k
            gs_free_object(pdir->ccache.bits_memory, chunk->data, "gs_font_dir_finalize");
312
374k
            gs_free_object(pdir->ccache.bits_memory, chunk, "gs_font_dir_finalize");
313
374k
            break;
314
374k
        }
315
316
40.2k
        prev_chunk = chunk;
317
40.2k
        chunk = chunk->next;
318
40.2k
        gs_free_object(pdir->ccache.bits_memory, prev_chunk->data, "gs_font_dir_finalize");
319
40.2k
        gs_free_object(pdir->ccache.bits_memory, prev_chunk, "gs_font_dir_finalize");
320
40.2k
    }
321
374k
    pdir->ccache.chunks = NULL;
322
374k
}
323
void
324
gs_font_dir_free(gs_font_dir *dir)
325
16.1k
{
326
16.1k
    if (dir == NULL)
327
0
        return;
328
16.1k
    gs_free_object(dir->memory, dir, "gs_font_dir_free");
329
16.1k
}
330
331
/* Allocate and minimally initialize a font. */
332
gs_font *
333
gs_font_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
334
              const gs_font_procs *procs, gs_font_dir *dir,
335
              client_name_t cname)
336
257k
{
337
257k
    gs_font *pfont = gs_alloc_struct(mem, gs_font, pstype, cname);
338
339
257k
    if (pfont == 0)
340
0
        return 0;
341
257k
#if 1 /* Clear entire structure to avoid unitialized pointers
342
         when the initialization exits prematurely by error. */
343
257k
    memset(pfont, 0, pstype->ssize);
344
257k
    pfont->memory = mem;
345
257k
    pfont->dir = dir;
346
257k
    gs_font_notify_init(pfont);
347
257k
    pfont->id = gs_next_ids(mem, 1);
348
257k
    pfont->base = pfont;
349
257k
    pfont->ExactSize = pfont->InBetweenSize = pfont->TransformedChar =
350
257k
        fbit_use_outlines;
351
257k
    pfont->procs = *procs;
352
#else
353
    /* For clarity we leave old initializations here
354
       to know which fields needs to be initialized. */
355
    pfont->next = pfont->prev = 0;
356
    pfont->memory = mem;
357
    pfont->dir = dir;
358
    pfont->is_resource = false;
359
    gs_font_notify_init(pfont);
360
    pfont->id = gs_next_ids(mem, 1);
361
    pfont->base = pfont;
362
    pfont->client_data = 0;
363
    /* not FontMatrix, FontType */
364
    pfont->BitmapWidths = false;
365
    pfont->ExactSize = pfont->InBetweenSize = pfont->TransformedChar =
366
        fbit_use_outlines;
367
    pfont->WMode = 0;
368
    pfont->PaintType = 0;
369
    pfont->StrokeWidth = 0;
370
    pfont->is_cached = false;
371
    pfont->procs = *procs;
372
    memset(&pfont->orig_FontMatrix, 0, sizeof(pfont->orig_FontMatrix));
373
#endif
374
    /* not key_name, font_name */
375
257k
    return pfont;
376
257k
}
377
/* Allocate and minimally initialize a base font. */
378
gs_font_base *
379
gs_font_base_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
380
                   const gs_font_procs *procs, gs_font_dir *dir,
381
                   client_name_t cname)
382
0
{
383
0
    gs_font_base *pfont =
384
0
        (gs_font_base *)gs_font_alloc(mem, pstype, procs, dir, cname);
385
386
0
    if (pfont == 0)
387
0
        return 0;
388
0
    pfont->FontBBox.p.x = pfont->FontBBox.p.y =
389
0
        pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0;
390
0
    uid_set_invalid(&pfont->UID);
391
0
    pfont->encoding_index = pfont->nearest_encoding_index = -1;
392
0
    return pfont;
393
0
}
394
395
/* Initialize the notification list for a font. */
396
void
397
gs_font_notify_init(gs_font *font)
398
277k
{
399
    /*
400
     * The notification list for a font must be allocated in the font's
401
     * stable memory, because of the following possible sequence of events:
402
     *
403
     *   - Allocate font X in local VM.
404
     *   - Client A registers for notification when X is freed.
405
     *   - 'save'
406
     *   - Client B registers for notification when X is freed.
407
     *   - 'restore'
408
     *
409
     * If the notification list element for client B is allocated in
410
     * restorable local VM (i.e., the same VM as the font), then when the
411
     * 'restore' occurs, either the list element will be deleted (not what
412
     * client B wants, because font X hasn't been freed yet), or there will
413
     * be a dangling pointer.
414
     */
415
277k
    gs_notify_init(&font->notify_list, gs_memory_stable(font->memory));
416
277k
}
417
418
/*
419
 * Register/unregister a client for notification by a font.  Currently
420
 * the clients are only notified when a font is freed.  Note that any
421
 * such client must unregister itself when *it* is freed.
422
 */
423
int
424
gs_font_notify_register(gs_font *font, gs_notify_proc_t proc, void *proc_data)
425
1.99M
{
426
1.99M
    return gs_notify_register(&font->notify_list, proc, proc_data);
427
1.99M
}
428
int
429
gs_font_notify_unregister(gs_font *font, gs_notify_proc_t proc, void *proc_data)
430
1.99M
{
431
1.99M
    return gs_notify_unregister(&font->notify_list, proc, proc_data);
432
1.99M
}
433
434
/* Link an element at the head of a chain. */
435
static void
436
font_link_first(gs_font **pfirst, gs_font *elt)
437
2.85M
{
438
2.85M
    gs_font *first = elt->next = *pfirst;
439
440
2.85M
    if (first)
441
2.60M
        first->prev = elt;
442
2.85M
    elt->prev = 0;
443
2.85M
    *pfirst = elt;
444
2.85M
}
445
446
/* definefont */
447
/* Use this only for original (unscaled) fonts! */
448
/* Note that it expects pfont->procs.define_font to be set already. */
449
int
450
gs_definefont(gs_font_dir * pdir, gs_font * pfont)
451
2.83M
{
452
2.83M
    int code;
453
454
2.83M
    pfont->dir = pdir;
455
2.83M
    pfont->base = pfont;
456
2.83M
    code = (*pfont->procs.define_font) (pdir, pfont);
457
2.83M
    if (code < 0) {   /* Make sure we don't try to finalize this font. */
458
0
        pfont->base = 0;
459
0
        return code;
460
0
    }
461
2.83M
    font_link_first(&pdir->orig_fonts, pfont);
462
2.83M
    if_debug2m('m', pfont->memory, "[m]defining font "PRI_INTPTR", next="PRI_INTPTR"\n",
463
2.83M
               (intptr_t)pfont, (intptr_t)pfont->next);
464
2.83M
    return 0;
465
2.83M
}
466
467
/* Find a sililar registered font of same type. */
468
int
469
gs_font_find_similar(const gs_font_dir * pdir, const gs_font **ppfont,
470
                       int (*similar)(const gs_font *, const gs_font *))
471
137
{
472
137
    const gs_font *pfont0 = *ppfont;
473
137
    const gs_font *pfont1 = pdir->orig_fonts;
474
475
416
    for (; pfont1 != NULL; pfont1 = pfont1->next) {
476
279
        if (pfont1 != pfont0 && pfont1->FontType == pfont0->FontType) {
477
142
            int code = similar(pfont0, pfont1);
478
142
            if (code != 0) {
479
0
                *ppfont = pfont1;
480
0
                return code;
481
0
            }
482
142
        }
483
279
    }
484
137
    return 0;
485
137
}
486
487
/* scalefont */
488
int
489
gs_scalefont(gs_font_dir * pdir, const gs_font * pfont, double scale,
490
             gs_font ** ppfont)
491
0
{
492
0
    gs_matrix mat;
493
494
0
    gs_make_scaling(scale, scale, &mat);
495
0
    return gs_makefont(pdir, pfont, &mat, ppfont);
496
0
}
497
498
/* makefont */
499
int
500
gs_makefont(gs_font_dir * pdir, const gs_font * pfont,
501
            const gs_matrix * pmat, gs_font ** ppfont)
502
27.0k
{
503
27.0k
    int code;
504
27.0k
    gs_font *prev = 0;
505
27.0k
    gs_font *pf_out = pdir->scaled_fonts;
506
27.0k
    gs_memory_t *mem = pfont->memory;
507
27.0k
    gs_matrix newmat;
508
27.0k
    bool can_cache;
509
510
27.0k
    if ((code = gs_matrix_multiply(&pfont->FontMatrix, pmat, &newmat)) < 0)
511
0
        return code;
512
    /*
513
     * Check for the font already being in the scaled font cache.
514
     * Until version 5.97, we only cached scaled fonts if the base
515
     * (unscaled) font had a valid UniqueID or XUID; now, we will cache
516
     * scaled versions of any non-composite font.
517
     */
518
#ifdef DEBUG
519
    if (gs_debug_c('m')) {
520
        const gs_font_base *const pbfont = (const gs_font_base *)pfont;
521
522
        if (pfont->FontType == ft_composite)
523
            dmlprintf(mem, "[m]composite");
524
        else if (uid_is_UniqueID(&pbfont->UID))
525
            dmlprintf1(mem, "[m]UniqueID=%ld", pbfont->UID.id);
526
        else if (uid_is_XUID(&pbfont->UID))
527
            dmlprintf1(mem, "[m]XUID(%u)", (uint) (-pbfont->UID.id));
528
        else
529
            dmlprintf(mem, "[m]no UID");
530
        dmprintf8(mem, ", FontType=%d, base="PRI_INTPTR",\n[m]  new FontMatrix=[%g %g %g %g %g %g]\n",
531
                 pfont->FontType, (intptr_t)pfont->base,
532
                 pmat->xx, pmat->xy, pmat->yx, pmat->yy,
533
                 pmat->tx, pmat->ty);
534
    }
535
#endif
536
    /*
537
     * Don't try to cache scaled composite fonts, because of the side
538
     * effects on FDepVector and descendant fonts that occur in makefont.
539
     */
540
27.0k
    if (pfont->FontType != ft_composite) {
541
303k
        for (; pf_out != 0; prev = pf_out, pf_out = pf_out->next)
542
283k
            if (pf_out->FontType == pfont->FontType &&
543
283k
                pf_out->base == pfont->base &&
544
192k
                pf_out->FontMatrix.xx == newmat.xx &&
545
33.6k
                pf_out->FontMatrix.xy == newmat.xy &&
546
33.6k
                pf_out->FontMatrix.yx == newmat.yx &&
547
33.6k
                pf_out->FontMatrix.yy == newmat.yy &&
548
33.6k
                pf_out->FontMatrix.tx == newmat.tx &&
549
7.52k
                pf_out->FontMatrix.ty == newmat.ty
550
283k
                ) {
551
7.52k
                *ppfont = pf_out;
552
7.52k
                if_debug1m('m', pfont->memory, "[m]found font="PRI_INTPTR"\n", (intptr_t)pf_out);
553
7.52k
                return 0;
554
7.52k
            }
555
19.5k
        can_cache = true;
556
19.5k
    } else
557
0
        can_cache = false;
558
19.5k
    pf_out = gs_alloc_struct(mem, gs_font, gs_object_type(mem, pfont),
559
19.5k
                             "gs_makefont");
560
19.5k
    if (!pf_out)
561
0
        return_error(gs_error_VMerror);
562
19.5k
    memcpy(pf_out, pfont, gs_object_size(mem, pfont));
563
19.5k
    gs_font_notify_init(pf_out);
564
19.5k
    pf_out->FontMatrix = newmat;
565
19.5k
    pf_out->client_data = 0;
566
19.5k
    pf_out->dir = pdir;
567
19.5k
    pf_out->base = pfont->base;
568
19.5k
    *ppfont = pf_out;
569
19.5k
    code = (*pf_out->procs.make_font) (pdir, pfont, pmat, ppfont);
570
19.5k
    if (code < 0)
571
0
        return code;
572
19.5k
    if (can_cache) {
573
19.5k
        if (pdir->ssize >= pdir->smax && prev != 0) {
574
            /*
575
             * We must discard a cached scaled font.
576
             * prev points to the last (oldest) font.
577
             * (We can't free it, because there might be
578
             * other references to it.)
579
             */
580
2.29k
            if_debug1m('m', pfont->memory, "[m]discarding font "PRI_INTPTR"\n",
581
2.29k
                      (intptr_t)prev);
582
2.29k
            if (prev->prev != 0)
583
2.29k
                prev->prev->next = 0;
584
0
            else
585
0
                pdir->scaled_fonts = 0;
586
2.29k
            pdir->ssize--;
587
2.29k
            prev->prev = 0;
588
            /* This comment is a relatively new reconstruction of old assumptions,
589
               which were done 5+ years ago (see gsfont.c revision 1.1).
590
               Here the font is only removed from the pdir->scaled_fonts list
591
               to prevent the latter to grow huge. Thus the list is used only to
592
               merge scaled font duplicates by the 'for' loop in the beginning
593
               of this function. We do not discard related character rasters
594
               from character cache due to 3 reasons :
595
               1. At this point a cached_char instance may be referred
596
                  by one or more gs_show_enum instances, which may exist on the
597
                  PS estack while execution of a Type 3 BuildChar or BuildGlyph.
598
                  Such event really happens while rendering a re-distilled tpc2.ps .
599
                  We must not remove those isntances, but currently there is no
600
                  mechanizm for distinguishing them from othgers.
601
               2. If the font has an UID, another scaled font may use same fm_pair
602
                  instance due to different CTMs. Therefore same character rasters
603
                  may be useful for another scaled font.
604
               3. We don't know whether the font will be used again in nearest
605
                  future. Maybe it will be used again in the next 'show' operation.
606
                  Therefore we delay the decision about discarding character
607
                  rasters untill we need to release memory from them.
608
               4. Also note that the last created font, rather than the last used one,
609
                  is being discarded. An useful improvement would be
610
                  to move a font t the beginning of the list whenever it
611
                  appears in a show-like operation.
612
             */
613
#if 0     /* We disabled this code portion due to Bug 688392.
614
               The problem was dangling pointers, which appear in fm_pair instances
615
               after uid_free is applied to a font's UID,
616
               because they share same xvalues array. We're unable to guess
617
               for which reason uid_free was applied to the font's UID here
618
               5+ years ago (see gsfont.c revision 1.1).
619
               We do not remove this code portion until we get
620
               a complete understanding.
621
             */
622
            if (prev->FontType != ft_composite) {
623
                if_debug1m('m', pfont->memory, "[m]discarding UID 0x%lx\n",
624
                           (ulong) ((gs_font_base *) prev)->
625
                           UID.xvalues);
626
                uid_free(&((gs_font_base *) prev)->UID,
627
                         prev->memory,
628
                         "gs_makefont(discarding)");
629
                uid_set_invalid(&((gs_font_base *) prev)->UID);
630
            }
631
#endif
632
2.29k
        }
633
19.5k
        pdir->ssize++;
634
19.5k
        font_link_first(&pdir->scaled_fonts, pf_out);
635
19.5k
    } else {     /* Prevent garbage pointers. */
636
0
        pf_out->next = pf_out->prev = 0;
637
0
    }
638
19.5k
    if_debug2m('m', pfont->memory, "[m]new font="PRI_INTPTR" can_cache=%s\n",
639
19.5k
               (intptr_t)*ppfont, (can_cache ? "true" : "false"));
640
19.5k
    return 1;
641
19.5k
}
642
643
/* Set the current font.  This is provided only for the benefit of cshow, */
644
/* which must reset the current font without disturbing the root font. */
645
void
646
gs_set_currentfont(gs_gstate * pgs, gs_font * pfont)
647
529k
{
648
529k
    pgs->font = pfont;
649
529k
    pgs->char_tm_valid = false;
650
529k
}
651
652
/* setfont */
653
int
654
gs_setfont(gs_gstate * pgs, gs_font * pfont)
655
16.6M
{
656
16.6M
    pgs->font = pgs->root_font = pfont;
657
16.6M
    pgs->char_tm_valid = false;
658
16.6M
    return 0;
659
16.6M
}
660
661
/* currentfont */
662
gs_font *
663
gs_currentfont(const gs_gstate * pgs)
664
1.68M
{
665
1.68M
    return pgs->font;
666
1.68M
}
667
668
/* rootfont */
669
gs_font *
670
gs_rootfont(const gs_gstate * pgs)
671
27.8M
{
672
27.8M
    return pgs->root_font;
673
27.8M
}
674
675
/* cachestatus */
676
void
677
gs_cachestatus(register const gs_font_dir * pdir, register uint pstat[7])
678
1.04M
{
679
1.04M
    pstat[0] = pdir->ccache.bsize;
680
1.04M
    pstat[1] = pdir->ccache.bmax;
681
1.04M
    pstat[2] = pdir->fmcache.msize;
682
1.04M
    pstat[3] = pdir->fmcache.mmax;
683
1.04M
    pstat[4] = pdir->ccache.csize;
684
1.04M
    pstat[5] = pdir->ccache.cmax;
685
1.04M
    pstat[6] = pdir->ccache.upper;
686
1.04M
}
687
688
/* setcacheparams */
689
int
690
gs_setcachesize(gs_gstate * pgs, gs_font_dir * pdir, uint size)
691
0
{
692
0
    gs_memory_t *stable_mem = pdir->memory->stable_memory;
693
0
    if (size < 100000)             /* limits derived from CPSI emulation (CET 27-07) */
694
0
        size = 100000;
695
0
    else if (size > 100000000)
696
0
        size = 100000000;
697
698
    /* Changing the cache size precipitates rebuilding the cache data
699
       structures.  Start with freeing cached chars and fm pairs. */
700
0
    {
701
0
        gs_font *pfont;
702
0
        int code;
703
0
        for (pfont = pdir->scaled_fonts; pfont != 0; pfont = pfont->next) {
704
0
            code = gs_purge_font_from_char_caches_completely(pfont);
705
0
            if (code != 0)
706
0
                gs_rethrow_code(code);
707
708
0
        }
709
0
    }
710
711
    /* now free the cache structures and rebuild everything with the
712
       new cache size */
713
0
    gs_free_object(stable_mem, pdir->fmcache.mdata, "gs_setcachesize(mdata)");
714
0
    gs_free_object(stable_mem, pdir->ccache.table, "gs_setcachesize(table)");
715
0
    pdir->ccache.bmax = size;
716
0
    return gx_char_cache_alloc(stable_mem, stable_mem->non_gc_memory, pdir,
717
0
                               pdir->ccache.bmax, pdir->fmcache.mmax,
718
0
                               pdir->ccache.cmax, pdir->ccache.upper);
719
0
}
720
721
int
722
gs_setcachelower(gs_font_dir * pdir, uint size)
723
1.08M
{
724
1.08M
    pdir->ccache.lower = ((int)size < 0) ? 0 : size; /* ?: for CET 27-07 */
725
1.08M
    return 0;
726
1.08M
}
727
int
728
gs_setcacheupper(gs_font_dir * pdir, uint size)
729
1.08M
{
730
1.08M
    pdir->ccache.upper = ((int)size < 0) ? 0 : size; /* ?: for CET 27-06 */
731
1.08M
    return 0;
732
1.08M
}
733
int
734
gs_setaligntopixels(gs_font_dir * pdir, uint v)
735
580k
{
736
580k
    pdir->align_to_pixels = v;
737
580k
    return 0;
738
580k
}
739
int
740
gs_setgridfittt(gs_font_dir * pdir, uint v)
741
580k
{
742
580k
    pdir->grid_fit_tt = v;
743
580k
    return 0;
744
580k
}
745
746
/* currentcacheparams */
747
uint
748
gs_currentcachesize(const gs_font_dir * pdir)
749
1.04M
{
750
1.04M
    return pdir->ccache.bmax;
751
1.04M
}
752
uint
753
gs_currentcachelower(const gs_font_dir * pdir)
754
1.04M
{
755
1.04M
    return pdir->ccache.lower;
756
1.04M
}
757
uint
758
gs_currentcacheupper(const gs_font_dir * pdir)
759
1.04M
{
760
1.04M
    return pdir->ccache.upper;
761
1.04M
}
762
uint
763
gs_currentaligntopixels(const gs_font_dir * pdir)
764
87.9M
{
765
87.9M
    return pdir->align_to_pixels;
766
87.9M
}
767
uint
768
gs_currentgridfittt(const gs_font_dir * pdir)
769
779k
{
770
779k
    return pdir->grid_fit_tt;
771
779k
}
772
773
/* Purge a font from all font- and character-related tables. */
774
/* This is only used by restore (and, someday, the GC). */
775
int
776
gs_purge_font(gs_font * pfont)
777
2.15M
{
778
2.15M
    gs_font_dir *pdir = pfont->dir;
779
2.15M
    gs_font *pf;
780
781
    /* Remove the font from its list (orig_fonts or scaled_fonts). */
782
2.15M
    gs_font *prev = pfont->prev;
783
2.15M
    gs_font *next = pfont->next;
784
785
2.15M
    if (next != 0)
786
1.96M
        next->prev = prev, pfont->next = 0;
787
2.15M
    if (prev != 0)
788
0
        prev->next = next, pfont->prev = 0;
789
2.15M
    else if (pdir->orig_fonts == pfont)
790
2.15M
        pdir->orig_fonts = next;
791
15
    else if (pdir->scaled_fonts == pfont)
792
0
        pdir->scaled_fonts = next;
793
15
    else {     /* Shouldn't happen! */
794
15
        if_debug1m('u', pfont->memory, "purged font "PRI_INTPTR" not found\n", (intptr_t)pfont);
795
15
    }
796
797
    /* Purge the font from the scaled font cache. */
798
2.15M
    for (pf = pdir->scaled_fonts; pf != 0;) {
799
0
        if (pf->base == pfont) {
800
0
            int code = gs_purge_font(pf);
801
802
0
            if (code < 0)
803
0
                return code;
804
0
            pf = pdir->scaled_fonts;  /* start over */
805
0
        } else
806
0
            pf = pf->next;
807
0
    }
808
809
    /* Purge the font from the font/matrix pair cache, */
810
    /* including all cached characters rendered with that font. */
811
2.15M
    return gs_purge_font_from_char_caches(pfont);
812
2.15M
}
813
814
/* Locate a gs_font by gs_id. */
815
gs_font *
816
gs_find_font_by_id(gs_font_dir *pdir, gs_id id, gs_matrix *FontMatrix)
817
0
 {
818
0
    gs_font *pfont = pdir->orig_fonts;
819
820
0
    for(; pfont != NULL; pfont = pfont->next)
821
0
        if(pfont->id == id &&
822
0
            !gs_matrix_compare(&pfont->FontMatrix, FontMatrix))
823
0
            return pfont;
824
0
    return NULL;
825
0
 }
826
827
/* ---------------- Default font procedures ---------------- */
828
829
/* ------ Font-level procedures ------ */
830
831
/* Default (vacuous) definefont handler. */
832
int
833
gs_no_define_font(gs_font_dir * pdir, gs_font * pfont)
834
2.83M
{
835
2.83M
    return 0;
836
2.83M
}
837
838
/* Default (vacuous) makefont handler. */
839
int
840
gs_no_make_font(gs_font_dir * pdir, const gs_font * pfont,
841
                const gs_matrix * pmat, gs_font ** ppfont)
842
0
{
843
0
    return 0;
844
0
}
845
/* Makefont handler for base fonts, which must copy the XUID. */
846
int
847
gs_base_make_font(gs_font_dir * pdir, const gs_font * pfont,
848
                  const gs_matrix * pmat, gs_font ** ppfont)
849
19.5k
{
850
19.5k
    return uid_copy(&((gs_font_base *)*ppfont)->UID, (*ppfont)->memory,
851
19.5k
                    "gs_base_make_font(XUID)");
852
19.5k
}
853
854
/* Default font info procedure */
855
int
856
gs_default_font_info(gs_font *font, const gs_point *pscale, int members,
857
                     gs_font_info_t *info)
858
153k
{
859
153k
    int wmode = font->WMode;
860
153k
    gs_font_base *bfont = (gs_font_base *)font;
861
153k
    gs_point scale;
862
153k
    gs_matrix smat;
863
153k
    const gs_matrix *pmat;
864
865
153k
    if (pscale == 0) {
866
153k
        scale.x = scale.y = 0;
867
153k
        pmat = 0;
868
153k
    } else {
869
0
        scale = *pscale;
870
0
        gs_make_scaling(scale.x, scale.y, &smat);
871
0
        pmat = &smat;
872
0
    }
873
153k
    info->members = 0;
874
153k
    if (members & FONT_INFO_FLAGS)
875
91.2k
        info->Flags_returned = 0;
876
153k
    if (font->FontType == ft_composite)
877
0
        return 0;   /* nothing available */
878
153k
    if (members & FONT_INFO_BBOX) {
879
91.2k
        info->BBox.p.x = (int)bfont->FontBBox.p.x;
880
91.2k
        info->BBox.p.y = (int)bfont->FontBBox.p.y;
881
91.2k
        info->BBox.q.x = (int)bfont->FontBBox.q.x;
882
91.2k
        info->BBox.q.y = (int)bfont->FontBBox.q.y;
883
91.2k
        info->Flags_returned |= FONT_INFO_BBOX;
884
91.2k
    }
885
153k
    if ((members & FONT_INFO_FLAGS) &&
886
91.2k
        (info->Flags_requested & FONT_IS_FIXED_WIDTH)
887
153k
        ) {
888
        /*
889
         * Scan the glyph space to compute the fixed width if any.
890
         */
891
91.2k
        gs_glyph notdef = GS_NO_GLYPH;
892
91.2k
        gs_glyph glyph;
893
91.2k
        int fixed_width = 0;
894
91.2k
        int index;
895
91.2k
        int code = 0; /* Quiet compiler. */
896
91.2k
        int ecode = 0;
897
91.2k
        bool has_glyphs = false;
898
899
91.2k
        for (index = 0;
900
4.84M
             fixed_width >= 0 &&
901
4.77M
             (code = font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_NAME, &glyph)) >= 0 &&
902
4.77M
                 index != 0;
903
4.75M
             ) {
904
4.75M
            gs_glyph_info_t glyph_info;
905
906
4.75M
            memset(&glyph_info, 0x00, sizeof(gs_glyph_info_t));
907
4.75M
            code = font->procs.glyph_info(font, glyph, pmat,
908
4.75M
                                          (GLYPH_INFO_WIDTH0 << wmode),
909
4.75M
                                          &glyph_info);
910
4.75M
            if (code < 0) {
911
308k
                ecode = code;
912
308k
                continue;
913
308k
            }
914
4.44M
            if (notdef == GS_NO_GLYPH && gs_font_glyph_is_notdef(bfont, glyph)) {
915
31.6k
                notdef = glyph;
916
31.6k
                info->MissingWidth = (int)glyph_info.width[wmode].x;
917
31.6k
                info->members |= FONT_INFO_MISSING_WIDTH;
918
31.6k
            }
919
4.44M
            if (glyph_info.width[wmode].y != 0)
920
0
                fixed_width = min_int;
921
4.44M
            else if (fixed_width == 0)
922
2.63M
                fixed_width = (int)glyph_info.width[wmode].x;
923
1.81M
            else if (glyph_info.width[wmode].x != fixed_width)
924
71.9k
                fixed_width = min_int;
925
4.44M
            has_glyphs = true;
926
4.44M
        }
927
91.2k
        if (ecode < 0 && !has_glyphs)
928
0
            return ecode;
929
91.2k
        if (fixed_width > 0) {
930
2.15k
            info->Flags |= FONT_IS_FIXED_WIDTH;
931
2.15k
            info->members |= FONT_INFO_AVG_WIDTH | FONT_INFO_MAX_WIDTH |
932
2.15k
                FONT_INFO_MISSING_WIDTH;
933
2.15k
            info->AvgWidth = info->MaxWidth = info->MissingWidth = fixed_width;
934
2.15k
        }
935
91.2k
        info->Flags_returned |= FONT_IS_FIXED_WIDTH;
936
91.2k
    } else if (members & FONT_INFO_MISSING_WIDTH) {
937
0
        gs_glyph glyph;
938
0
        int index;
939
940
0
        for (index = 0;
941
0
             font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_NAME, &glyph) >= 0 &&
942
0
                 index != 0;
943
0
             ) {
944
            /*
945
             * If this is a CIDFont or TrueType font that uses integers as
946
             * glyph names, check for glyph 0; otherwise, check for .notdef.
947
             */
948
0
            if (!gs_font_glyph_is_notdef(bfont, glyph))
949
0
                continue;
950
0
            {
951
0
                gs_glyph_info_t glyph_info;
952
0
                int code = font->procs.glyph_info(font, glyph, pmat,
953
0
                                                  (GLYPH_INFO_WIDTH0 << wmode),
954
0
                                                  &glyph_info);
955
956
0
                if (code < 0)
957
0
                    return code;
958
0
                info->MissingWidth = (int)glyph_info.width[wmode].x;
959
0
                info->members |= FONT_INFO_MISSING_WIDTH;
960
0
                break;
961
0
            }
962
0
        }
963
0
    }
964
153k
    return 0;
965
153k
}
966
967
/* Default font similarity testing procedure */
968
int
969
gs_default_same_font(const gs_font *font, const gs_font *ofont, int mask)
970
236
{
971
354
    while (font->base != font)
972
118
        font = font->base;
973
354
    while (ofont->base != ofont)
974
118
        ofont = ofont->base;
975
236
    if (ofont == font)
976
236
        return mask;
977
    /* In general, we can't determine similarity. */
978
0
    return 0;
979
236
}
980
int
981
gs_base_same_font(const gs_font *font, const gs_font *ofont, int mask)
982
0
{
983
0
    int same = gs_default_same_font(font, ofont, mask);
984
985
0
    if (!same) {
986
0
        const gs_font_base *const bfont = (const gs_font_base *)font;
987
0
        const gs_font_base *const obfont = (const gs_font_base *)ofont;
988
989
0
        if (mask & FONT_SAME_ENCODING) {
990
0
            if (bfont->encoding_index != ENCODING_INDEX_UNKNOWN ||
991
0
                obfont->encoding_index != ENCODING_INDEX_UNKNOWN
992
0
                ) {
993
0
                if (bfont->encoding_index == obfont->encoding_index)
994
0
                    same |= FONT_SAME_ENCODING;
995
0
            }
996
0
        }
997
0
    }
998
0
    return same;
999
0
}
1000
1001
/* ------ Glyph-level procedures ------ */
1002
1003
/*
1004
 * Test whether a glyph is the notdef glyph for a base font.
1005
 * The test is somewhat adhoc: perhaps this should be a virtual procedure.
1006
 */
1007
bool
1008
gs_font_glyph_is_notdef(gs_font_base *bfont, gs_glyph glyph)
1009
16.2M
{
1010
16.2M
    gs_const_string gnstr;
1011
1012
16.2M
    if (glyph == GS_NO_GLYPH)
1013
0
        return false;
1014
16.2M
    if (glyph >= GS_MIN_CID_GLYPH)
1015
286k
        return (glyph == GS_MIN_CID_GLYPH);
1016
15.9M
    return (bfont->procs.glyph_name((gs_font *)bfont, glyph, &gnstr) >= 0 &&
1017
15.9M
            gnstr.size == 7 && !memcmp(gnstr.data, ".notdef", 7));
1018
16.2M
}
1019
1020
/* Dummy character encoding procedure */
1021
gs_glyph
1022
gs_no_encode_char(gs_font *pfont, gs_char chr, gs_glyph_space_t glyph_space)
1023
0
{
1024
0
    return GS_NO_GLYPH;
1025
0
}
1026
1027
/* Dummy glyph decoding procedure */
1028
int
1029
gs_no_decode_glyph(gs_font *pfont, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length)
1030
0
{
1031
0
    return (int)GS_NO_CHAR;
1032
0
}
1033
1034
/* Dummy glyph enumeration procedure */
1035
int
1036
gs_no_enumerate_glyph(gs_font *font, int *pindex, gs_glyph_space_t glyph_space,
1037
                      gs_glyph *pglyph)
1038
0
{
1039
0
    return_error(gs_error_undefined);
1040
0
}
1041
1042
/* Default glyph info procedure */
1043
int
1044
gs_default_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
1045
                      int members, gs_glyph_info_t *info)
1046
2.24M
{   /* WMode may be inherited from an upper font. */
1047
2.24M
    gx_path path;
1048
2.24M
    int returned = 0;
1049
2.24M
    int code;
1050
2.24M
    int wmode = ((members & GLYPH_INFO_WIDTH1) != 0);
1051
2.24M
    double sbw[4] = {0, 0, 0, 0};
1052
    /* Currently glyph_outline retrieves sbw only with type 1,2,9 fonts. */
1053
2.24M
    bool charstrings_font = (font->FontType == ft_encrypted ||
1054
809k
                             font->FontType == ft_encrypted2 ||
1055
516k
                             font->FontType == ft_CID_encrypted);
1056
1057
2.24M
    gx_path_init_bbox_accumulator(&path);
1058
2.24M
    code = gx_path_add_point(&path, fixed_0, fixed_0);
1059
2.24M
    if (code < 0)
1060
0
        goto out;
1061
2.24M
    code = font->procs.glyph_outline(font, wmode, glyph, pmat, &path, sbw);
1062
2.24M
    if (code < 0)
1063
414k
        goto out;
1064
1.83M
    if (members & GLYPH_INFO_WIDTHS) {
1065
1.06M
        int wmode = font->WMode;
1066
1.06M
        int wmask = GLYPH_INFO_WIDTH0 << wmode;
1067
1068
1.06M
        if (members & wmask) {
1069
1.06M
            gs_fixed_point pt;
1070
1071
1.06M
            code = gx_path_current_point(&path, &pt);
1072
1.06M
            if (code < 0)
1073
0
                goto out;
1074
1.06M
            info->width[wmode].x = fixed2float(pt.x);
1075
1.06M
            info->width[wmode].y = fixed2float(pt.y);
1076
1.06M
            returned |= wmask;
1077
1.06M
        }
1078
1.06M
    }
1079
1.83M
    if (members & GLYPH_INFO_BBOX) {
1080
760k
        gs_fixed_rect bbox;
1081
1082
760k
        code = gx_path_bbox(&path, &bbox);
1083
760k
        if (code < 0)
1084
0
            goto out;
1085
760k
        info->bbox.p.x = fixed2float(bbox.p.x);
1086
760k
        info->bbox.p.y = fixed2float(bbox.p.y);
1087
760k
        info->bbox.q.x = fixed2float(bbox.q.x);
1088
760k
        info->bbox.q.y = fixed2float(bbox.q.y);
1089
760k
        returned |= GLYPH_INFO_BBOX;
1090
760k
    }
1091
1.83M
    if (members & (GLYPH_INFO_WIDTH0 << wmode) && charstrings_font) {
1092
1.06M
        if (pmat == 0) {
1093
19.1k
            info->width[wmode].x = sbw[2];
1094
19.1k
            info->width[wmode].y = sbw[3];
1095
1.04M
        } else {
1096
1.04M
            code = gs_distance_transform(sbw[2], sbw[3], pmat, &info->width[wmode]);
1097
1.04M
            if (code < 0)
1098
0
                return code;
1099
1.04M
        }
1100
1.06M
        returned |= GLYPH_INFO_WIDTH0 << wmode;
1101
1.06M
    }
1102
1.83M
    if (members & (GLYPH_INFO_VVECTOR0 << wmode) && charstrings_font) {
1103
18.6k
        if (pmat == 0) {
1104
18.6k
            info->v.x = sbw[0];
1105
18.6k
            info->v.y = sbw[1];
1106
18.6k
        } else {
1107
0
            code = gs_distance_transform(sbw[0], sbw[1], pmat, &info->v);
1108
0
            if (code < 0)
1109
0
                return code;
1110
0
        }
1111
18.6k
        returned |= GLYPH_INFO_VVECTOR0 << wmode;
1112
18.6k
    }
1113
1.83M
    if (members & GLYPH_INFO_NUM_PIECES) {
1114
1.05M
        info->num_pieces = 0;
1115
1.05M
        returned |= GLYPH_INFO_NUM_PIECES;
1116
1.05M
    }
1117
1.83M
    returned |= members & GLYPH_INFO_PIECES; /* no pieces stored */
1118
2.24M
 out:
1119
2.24M
    info->members = returned;
1120
2.24M
    return code;
1121
1.83M
}
1122
1123
/* Dummy glyph outline procedure */
1124
int
1125
gs_no_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat,
1126
                    gx_path *ppath, double sbw[4])
1127
400k
{
1128
400k
    return_error(gs_error_undefined);
1129
400k
}
1130
1131
/* Dummy glyph name procedure */
1132
int
1133
gs_no_glyph_name(gs_font *font, gs_glyph glyph, gs_const_string *pstr)
1134
0
{
1135
0
    return_error(gs_error_undefined);
1136
0
}
1137
1138
#ifdef DEBUG
1139
/* Reserve a text enumerator instance id. */
1140
ulong gs_next_text_enum_id(const gs_font *font)
1141
{
1142
    return ++font->dir->text_enum_id;
1143
}
1144
#endif