Coverage Report

Created: 2025-06-10 06:58

/src/ghostpdl/base/gxfapi.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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
#include "memory_.h"
18
19
#include "gsmemory.h"
20
#include "gserrors.h"
21
#include "gxdevice.h"
22
#include "gxfont.h"
23
#include "gxfont1.h"
24
#include "gxpath.h"
25
#include "gxfcache.h"
26
#include "gxchrout.h"
27
#include "gximask.h"
28
#include "gscoord.h"
29
#include "gspaint.h"
30
#include "gspath.h"
31
#include "gzstate.h"
32
#include "gxfcid.h"
33
#include "gxchar.h"             /* for st_gs_show_enum and MAX_CCACHE_TEMP_BITMAP_BITS */
34
#include "gdebug.h"
35
#include "gsimage.h"
36
#include "gsbittab.h"
37
#include "gzpath.h"
38
#include "gxdevsop.h"
39
40
#include "gxfapi.h"
41
42
2.38k
#define FAPI_ROUND(v) (v >= 0 ? v + 0.5 : v - 0.5)
43
2.38k
#define FAPI_ROUND_TO_FRACINT(v) ((fracint)FAPI_ROUND(v))
44
45
extern_gs_get_fapi_server_inits();
46
47
/* FIXME */
48
static int
49
gs_fapi_renderer_retcode(gs_memory_t *mem, gs_fapi_server *I,
50
                         gs_fapi_retcode rc)
51
404k
{
52
404k
    if (rc == 0)
53
403k
        return 0;
54
479
    if (gs_debug_c('1')) {
55
0
        emprintf2(mem,
56
0
                  "Error: Font Renderer Plugin ( %s ) return code = %d\n",
57
0
                  I->ig.d->subtype, rc);
58
0
    }
59
479
    return rc < 0 ? rc : gs_error_invalidfont;
60
404k
}
61
62
typedef struct gs_fapi_outline_handler_s
63
{
64
    gs_fapi_server *fserver;
65
    struct gx_path_s *path;
66
    fixed x0;
67
    fixed y0;
68
    bool close_path;
69
    bool need_close;            /* This stuff fixes unclosed paths being rendered with UFST */
70
} gs_fapi_outline_handler;
71
72
static inline int64_t
73
import_shift(int64_t x, int64_t n)
74
72.4k
{
75
72.4k
    return (n > 0 ? (x << n) : (x >> -n));
76
72.4k
}
77
78
static inline int
79
export_shift(int x, int n)
80
1.61k
{
81
1.61k
    return (n > 0 ? (x >> n) : (x << -n));
82
1.61k
}
83
84
static inline int
85
fapi_round(double x)
86
0
{
87
0
    return (int)(x + 0.5);
88
0
}
89
90
static int
91
add_closepath(gs_fapi_path *I)
92
3.32k
{
93
3.32k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
94
95
3.32k
    if (olh->need_close == true) {
96
2.74k
        olh->need_close = false;
97
2.74k
        I->gs_error = gx_path_close_subpath_notes(olh->path, 0);
98
2.74k
    }
99
3.32k
    return (I->gs_error);
100
3.32k
}
101
102
static int
103
add_move(gs_fapi_path *I, int64_t x, int64_t y)
104
2.76k
{
105
2.76k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
106
107
2.76k
    x = import_shift(x, I->shift);
108
2.76k
    y = -import_shift(y, I->shift);
109
2.76k
    if (olh->fserver->transform_outline) {
110
0
        gs_point pt;
111
0
        I->gs_error = gs_distance_transform((double)fixed2float((float)x), (double)fixed2float((float)y), &olh->fserver->outline_mat, &pt);
112
0
        if (I->gs_error < 0)
113
0
            return I->gs_error;
114
0
        x = float2fixed(pt.x);
115
0
        y = float2fixed(pt.y);
116
0
    }
117
2.76k
    x += olh->x0;
118
2.76k
    y += olh->y0;
119
120
2.76k
    if (x > (int64_t) max_coord_fixed || x < (int64_t) min_coord_fixed
121
2.76k
     || y > (int64_t) max_coord_fixed || y < (int64_t) min_coord_fixed) {
122
12
         I->gs_error = gs_error_undefinedresult;
123
12
    }
124
2.75k
    else {
125
126
2.75k
        if (olh->need_close && olh->close_path)
127
1.17k
            if ((I->gs_error = add_closepath(I)) < 0)
128
0
                return (I->gs_error);
129
2.75k
        olh->need_close = false;
130
131
/*        dprintf2("%f %f moveto\n", fixed2float(x), fixed2float(y)); */
132
2.75k
        I->gs_error = gx_path_add_point(olh->path, (fixed) x, (fixed) y);
133
2.75k
    }
134
2.76k
    return (I->gs_error);
135
2.76k
}
136
137
static int
138
add_line(gs_fapi_path *I, int64_t x, int64_t y)
139
14.0k
{
140
14.0k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
141
142
14.0k
    x = import_shift(x, I->shift);
143
14.0k
    y = -import_shift(y, I->shift);
144
14.0k
    if (olh->fserver->transform_outline) {
145
0
        gs_point pt;
146
0
        I->gs_error = gs_distance_transform((double)fixed2float((float)x), (double)fixed2float((float)y), &olh->fserver->outline_mat, &pt);
147
0
        if (I->gs_error < 0)
148
0
            return I->gs_error;
149
0
        x = float2fixed(pt.x);
150
0
        y = float2fixed(pt.y);
151
0
    }
152
14.0k
    x += olh->x0;
153
14.0k
    y += olh->y0;
154
155
14.0k
    if (x > (int64_t) max_coord_fixed || x < (int64_t) min_coord_fixed
156
14.0k
     || y > (int64_t) max_coord_fixed || y < (int64_t) min_coord_fixed) {
157
0
         I->gs_error = gs_error_undefinedresult;
158
0
    }
159
14.0k
    else {
160
14.0k
        olh->need_close = true;
161
162
/*        dprintf2("%f %f lineto\n", fixed2float(x), fixed2float(y)); */
163
14.0k
        I->gs_error = gx_path_add_line_notes(olh->path, (fixed) x, (fixed) y, 0);
164
14.0k
    }
165
14.0k
    return (I->gs_error);
166
14.0k
}
167
168
static int
169
add_curve(gs_fapi_path *I, int64_t x0, int64_t y0, int64_t x1, int64_t y1,
170
          int64_t x2, int64_t y2)
171
6.45k
{
172
6.45k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
173
174
6.45k
    x0 = import_shift(x0, I->shift);
175
6.45k
    y0 = -import_shift(y0, I->shift);
176
6.45k
    x1 = import_shift(x1, I->shift);
177
6.45k
    y1 = -import_shift(y1, I->shift);
178
6.45k
    x2 = import_shift(x2, I->shift);
179
6.45k
    y2 = -import_shift(y2, I->shift);
180
181
6.45k
    if (olh->fserver->transform_outline) {
182
0
        gs_point pt;
183
0
        I->gs_error = gs_distance_transform((double)fixed2float((float)x0), (double)fixed2float((float)y0), &olh->fserver->outline_mat, &pt);
184
0
        if (I->gs_error < 0)
185
0
            return I->gs_error;
186
0
        x0 = float2fixed(pt.x);
187
0
        y0 = float2fixed(pt.y);
188
0
        I->gs_error = gs_distance_transform((double)fixed2float((float)x1), (double)fixed2float((float)y1), &olh->fserver->outline_mat, &pt);
189
0
        if (I->gs_error < 0)
190
0
            return I->gs_error;
191
0
        x1 = float2fixed(pt.x);
192
0
        y1 = float2fixed(pt.y);
193
0
        I->gs_error = gs_distance_transform((double)fixed2float((float)x2), (double)fixed2float((float)y2), &olh->fserver->outline_mat, &pt);
194
0
        if (I->gs_error < 0)
195
0
            return I->gs_error;
196
0
        x2 = float2fixed(pt.x);
197
0
        y2 = float2fixed(pt.y);
198
0
    }
199
6.45k
    x0 += olh->x0;
200
6.45k
    y0 += olh->y0;
201
6.45k
    x1 += olh->x0;
202
6.45k
    y1 += olh->y0;
203
6.45k
    x2 += olh->x0;
204
6.45k
    y2 += olh->y0;
205
206
6.45k
    if (x0 > (int64_t) max_coord_fixed || x0 < (int64_t) min_coord_fixed
207
6.45k
     || y0 > (int64_t) max_coord_fixed || y0 < (int64_t) min_coord_fixed
208
6.45k
     || x1 > (int64_t) max_coord_fixed || x1 < (int64_t) min_coord_fixed
209
6.45k
     || y1 > (int64_t) max_coord_fixed || y1 < (int64_t) min_coord_fixed
210
6.45k
     || x2 > (int64_t) max_coord_fixed || x2 < (int64_t) min_coord_fixed
211
6.45k
     || y2 > (int64_t) max_coord_fixed || y2 < (int64_t) min_coord_fixed)
212
6
    {
213
6
        I->gs_error = gs_error_undefinedresult;
214
6
    }
215
6.44k
    else {
216
6.44k
        olh->need_close = true;
217
218
/*        dprintf6("%f %f %f %f %f %f curveto\n", fixed2float(x0), fixed2float(y0), fixed2float(x1), fixed2float(y1), fixed2float(x2), fixed2float(y2));*/
219
6.44k
        I->gs_error = gx_path_add_curve_notes(olh->path, (fixed) x0, (fixed) y0, (fixed) x1, (fixed) y1, (fixed) x2, (fixed) y2, 0);
220
6.44k
    }
221
6.45k
    return (I->gs_error);
222
6.45k
}
223
224
static gs_fapi_path path_interface_stub =
225
    { NULL, 0, 0, add_move, add_line, add_curve, add_closepath };
226
227
int
228
gs_fapi_get_metrics_count(gs_fapi_font *ff)
229
108k
{
230
108k
    if (!ff->is_type1 && ff->is_cid) {
231
1.88k
        gs_font_cid2 *pfcid = (gs_font_cid2 *) ff->client_font_data;
232
233
1.88k
        return (pfcid->cidata.MetricsCount);
234
1.88k
    }
235
106k
    return 0;
236
108k
}
237
238
/*
239
 * Lifted from psi/zchar.c
240
 * Return true if we only need the width from the rasterizer
241
 * and can short-circuit the full rendering of the character,
242
 * false if we need the actual character bits.  This is only safe if
243
 * we know the character is well-behaved, i.e., is not defined by an
244
 * arbitrary PostScript procedure.
245
 */
246
static inline bool
247
fapi_gs_char_show_width_only(const gs_text_enum_t *penum)
248
6.35k
{
249
6.35k
    if (!gs_text_is_width_only(penum))
250
5.08k
        return false;
251
1.26k
    switch (penum->orig_font->FontType) {
252
291
        case ft_encrypted:
253
291
        case ft_encrypted2:
254
291
        case ft_CID_encrypted:
255
291
        case ft_CID_TrueType:
256
291
        case ft_CID_bitmap:
257
291
        case ft_TrueType:
258
291
            return true;
259
977
        default:
260
977
            return false;
261
1.26k
    }
262
1.26k
}
263
264
265
266
/* If we're rendering an uncached glyph, we need to know
267
 * whether we're filling it with a pattern, and whether
268
 * transparency is involved - if so, we have to produce
269
 * a path outline, and not a bitmap.
270
 */
271
static inline bool
272
using_transparency_pattern(gs_gstate *pgs)
273
6.34k
{
274
6.34k
    gx_device *dev = gs_currentdevice_inline(pgs);
275
276
6.34k
    return ((!gs_color_writes_pure(pgs)) && dev_proc(dev, dev_spec_op)(dev, gxdso_supports_pattern_transparency, NULL, 0));
277
6.34k
}
278
279
static inline bool
280
recreate_multiple_master(gs_font_base *pbfont)
281
6.35k
{
282
6.35k
    bool r = false;
283
6.35k
    gs_fapi_server *I = pbfont->FAPI;
284
6.35k
    bool changed = false;
285
286
6.35k
    if (I && I->face.font_id != gs_no_id &&
287
6.35k
        (pbfont->FontType == ft_encrypted
288
6.15k
        || pbfont->FontType == ft_encrypted2)) {
289
3.14k
        gs_font_type1 *pfont1 = (gs_font_type1 *) pbfont;
290
3.14k
        if (pfont1->data.WeightVector.count != 0
291
3.14k
            && I->face.WeightVector.count != pfont1->data.WeightVector.count) {
292
0
            changed = true;
293
0
        }
294
3.14k
        else if (pfont1->data.WeightVector.count != 0) {
295
0
            changed = (memcmp(I->face.WeightVector.values, pfont1->data.WeightVector.values,
296
0
                             pfont1->data.WeightVector.count * sizeof(pfont1->data.WeightVector.values[0])) != 0);
297
0
        }
298
299
3.14k
        if (changed) {
300
0
            r = (I->set_mm_weight_vector(I, &I->ff, pfont1->data.WeightVector.values, pfont1->data.WeightVector.count) == gs_error_invalidaccess);
301
0
            I->face.WeightVector.count = pfont1->data.WeightVector.count;
302
0
            memcpy(I->face.WeightVector.values, pfont1->data.WeightVector.values,
303
0
                   pfont1->data.WeightVector.count * sizeof(pfont1->data.WeightVector.values[0]));
304
0
        }
305
3.14k
    }
306
6.35k
    return r;
307
6.35k
}
308
309
static bool
310
produce_outline_char(gs_show_enum *penum_s,
311
                     gs_font_base *pbfont, int abits,
312
                     gs_log2_scale_point *log2_scale)
313
6.35k
{
314
6.35k
    gs_gstate *pgs = (gs_gstate *) penum_s->pgs;
315
316
6.35k
    log2_scale->x = 0;
317
6.35k
    log2_scale->y = 0;
318
319
    /* Checking both gx_compute_text_oversampling() result, and abits (below) may seem redundant,
320
     * and hopefully it will be soon, but for now, gx_compute_text_oversampling() could opt to
321
     * "oversample" sufficiently small glyphs (fwiw, I don't think gx_compute_text_oversampling is
322
     * working as intended in that respect), regardless of the device's anti-alias setting.
323
     * This was an old, partial solution for dropouts in small glyphs.
324
     */
325
6.35k
    gx_compute_text_oversampling(penum_s, (gs_font *) pbfont, abits,
326
6.35k
                                 log2_scale);
327
328
6.35k
    return (pgs->in_charpath || pbfont->PaintType != 0 ||
329
6.35k
            (pgs->in_cachedevice != CACHE_DEVICE_CACHING
330
6.34k
             && using_transparency_pattern((gs_gstate *) penum_s->pgs))
331
6.35k
            || (pgs->in_cachedevice != CACHE_DEVICE_CACHING
332
4.26k
                && (log2_scale->x > 0 || log2_scale->y > 0))
333
6.35k
            || (pgs->in_cachedevice != CACHE_DEVICE_CACHING && abits > 1));
334
6.35k
}
335
336
static inline void
337
gs_fapi_release_typeface(gs_fapi_server *I, void **server_font_data)
338
100k
{
339
100k
    I->release_typeface(I, *server_font_data);
340
100k
    I->face.font_id = gs_no_id;
341
100k
    if (I->ff.server_font_data == *server_font_data)
342
26.3k
        I->ff.server_font_data = 0;
343
100k
    *server_font_data = 0;
344
100k
}
345
346
static int
347
notify_remove_font(void *proc_data, void *event_data)
348
102k
{                               /* gs_font_finalize passes event_data == NULL, so check it here. */
349
102k
    if (event_data == NULL) {
350
102k
        gs_font_base *pbfont = proc_data;
351
102k
        gs_fapi_server *I = pbfont->FAPI;
352
353
102k
        if (pbfont->FAPI_font_data != 0) {
354
100k
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
355
100k
        }
356
102k
    }
357
102k
    return 0;
358
102k
}
359
360
int
361
gs_fapi_prepare_font(gs_font *pfont, gs_fapi_server *I, int subfont, const char *font_file_path,
362
                     gs_string *full_font_buf, const char *xlatmap, const char **decodingID)
363
102k
{                               /* Returns 1 iff BBox is set. */
364
    /* Cleans up server's font data if failed. */
365
366
    /* A renderer may need to access the top level font's data of
367
     * a CIDFontType 0 (FontType 9) font while preparing its subfonts,
368
     * and/or perform a completion action with the top level font after
369
     * its descendants are prepared. Therefore with such fonts
370
     * we first call get_scaled_font(..., FAPI_TOPLEVEL_BEGIN), then
371
     * get_scaled_font(..., i) with eash descendant font index i,
372
     * and then get_scaled_font(..., FAPI_TOPLEVEL_COMPLETE).
373
     * For other fonts we don't call with 'i'.
374
     *
375
     * Actually server's data for top level CIDFontTYpe 0 non-disk fonts should not be important,
376
     * because with non-disk fonts FAPI_do_char never deals with the top-level font,
377
     * but does with its descendants individually.
378
     * Therefore a recommendation for the renderer is don't build any special
379
     * data for the top-level non-disk font of CIDFontType 0, but return immediately
380
     * with success code and NULL data pointer.
381
     *
382
     * get_scaled_font may be called for same font at second time,
383
     * so the renderen must check whether the data is already built.
384
     */
385
102k
    gs_memory_t *mem = pfont->memory;
386
102k
    gs_font_base *pbfont = (gs_font_base *)pfont;
387
102k
    int code, bbox_set = 0;
388
102k
    int BBox[4], scale;
389
102k
    int units[2];
390
102k
    double size;
391
102k
    gs_fapi_font_scale font_scale =
392
102k
        { {1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true };
393
394
102k
    scale = 1 << I->frac_shift;
395
102k
    size = 1 / hypot(pbfont->FontMatrix.xx, pbfont->FontMatrix.xy);
396
    /* I believe this is just to ensure minimal rounding problems with scalers that
397
       scale the FontBBox values with the font scale.
398
     */
399
102k
    if (size < 1000)
400
101k
        size = 1000;
401
402
102k
    font_scale.matrix[0] = font_scale.matrix[3] = (int)(size * scale + 0.5);
403
404
102k
    font_scale.HWResolution[0] = (fracint) (72 * scale);
405
102k
    font_scale.HWResolution[1] = (fracint) (72 * scale);
406
407
    /* The interpreter specific parts of the gs_fapi_font should
408
     * be assinged by the caller - now do the generic parts.
409
     */
410
102k
    I->ff.subfont = subfont;
411
102k
    I->ff.font_file_path = font_file_path;
412
102k
    I->ff.is_type1 = FAPI_ISTYPE1GLYPHDATA(pbfont);
413
102k
    I->ff.is_vertical = (pbfont->WMode != 0);
414
102k
    I->ff.memory = mem;
415
102k
    I->ff.client_ctx_p = I->client_ctx_p;
416
102k
    I->ff.client_font_data = pbfont;
417
102k
    I->ff.client_font_data2 = pbfont;
418
102k
    I->ff.server_font_data = pbfont->FAPI_font_data;    /* Possibly pass it from zFAPIpassfont. */
419
102k
    if (full_font_buf) {
420
82.4k
        I->ff.full_font_buf = (char *)full_font_buf->data;
421
82.4k
        I->ff.full_font_buf_len = full_font_buf->size;
422
82.4k
    }
423
19.6k
    else {
424
19.6k
        I->ff.full_font_buf = NULL;
425
19.6k
        I->ff.full_font_buf_len = 0;
426
19.6k
    }
427
102k
    I->ff.is_cid = FAPI_ISCIDFONT(pbfont);
428
102k
    I->ff.is_outline_font = pbfont->PaintType != 0;
429
430
102k
    if (!I->ff.is_mtx_skipped)
431
102k
        I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
432
433
102k
    if ((code = gs_fapi_renderer_retcode(mem, I, I->get_scaled_font(I, &I->ff,
434
102k
                                                                    (const
435
102k
                                                                     gs_fapi_font_scale
436
102k
                                                                     *)
437
102k
                                                                    &font_scale, xlatmap, gs_fapi_toplevel_begin)))
438
102k
        < 0)
439
246
        return code;
440
101k
    pbfont->FAPI_font_data = I->ff.server_font_data;    /* Save it back to GS font. */
441
442
    /* We only want to "refine" the FontBBox for fonts where we allow FAPI to be
443
       treated as a "black box", handing over the entire font to the FAPI server.
444
       That is, fonts where we give the server either the file, or a buffer with
445
       the entire font description in it.
446
     */
447
101k
    if (I->ff.server_font_data != 0
448
101k
        && (font_file_path != NULL || full_font_buf != NULL)) {
449
82.2k
        if ((code =
450
82.2k
             gs_fapi_renderer_retcode(mem, I,
451
82.2k
                                      I->get_font_bbox(I, &I->ff,
452
82.2k
                                                       BBox, units))) < 0) {
453
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
454
0
            return code;
455
0
        }
456
        /* Refine FontBBox : */
457
82.2k
        pbfont->FontBBox.p.x = ((double)BBox[0] / units[0]);
458
82.2k
        pbfont->FontBBox.p.y = ((double)BBox[1] / units[1]);
459
82.2k
        pbfont->FontBBox.q.x = ((double)BBox[2] / units[0]);
460
82.2k
        pbfont->FontBBox.q.y = ((double)BBox[3] / units[1]);
461
462
82.2k
        bbox_set = 1;
463
82.2k
    }
464
465
101k
    if (xlatmap != NULL && pbfont->FAPI_font_data != NULL) {
466
996
        if ((code =
467
996
             gs_fapi_renderer_retcode(mem, I,
468
996
                                      I->get_decodingID(I, &I->ff,
469
996
                                                        decodingID))) < 0) {
470
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
471
0
            return code;
472
0
        }
473
996
    }
474
475
    /* Prepare descendant fonts : */
476
101k
    if (font_file_path == NULL && I->ff.is_type1 && I->ff.is_cid) {     /* Renderers should expect same condition. */
477
186
        gs_font_cid0 *pfcid = (gs_font_cid0 *) pbfont;
478
186
        gs_font_type1 **FDArray = pfcid->cidata.FDArray;
479
186
        int i, n = pfcid->cidata.FDArray_size;
480
481
186
        I->ff.is_type1 = true;
482
186
        I->ff.is_vertical = false;      /* A subfont may be shared with another fonts. */
483
186
        I->ff.memory = mem;
484
186
        I->ff.client_ctx_p = I->client_ctx_p;
485
529
        for (i = 0; i < n; i++) {
486
347
            gs_font_type1 *pbfont1 = FDArray[i];
487
347
            int BBox_temp[4];
488
347
            int units_temp[2];
489
490
347
            pbfont1->FontBBox = pbfont->FontBBox;       /* Inherit FontBBox from the type 9 font. */
491
492
347
            I->ff.client_font_data = pbfont1;
493
347
            pbfont1->FAPI = pbfont->FAPI;
494
347
            I->ff.client_font_data2 = pbfont1;
495
347
            I->ff.server_font_data = pbfont1->FAPI_font_data;
496
347
            I->ff.is_cid = true;
497
347
            I->ff.is_outline_font = pbfont1->PaintType != 0;
498
347
            if (!I->ff.is_mtx_skipped)
499
347
                I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
500
347
            I->ff.subfont = 0;
501
347
            if ((code =
502
347
                 gs_fapi_renderer_retcode(mem, I,
503
347
                                          I->get_scaled_font(I, &I->ff,
504
347
                                                             (const
505
347
                                                              gs_fapi_font_scale
506
347
                                                              *)&font_scale,
507
347
                                                             NULL, i))) < 0) {
508
4
                break;
509
4
            }
510
511
343
            pbfont1->FAPI_font_data = I->ff.server_font_data;   /* Save it back to GS font. */
512
            /* Try to do something with the descendant font to ensure that it's working : */
513
343
            if ((code =
514
343
                 gs_fapi_renderer_retcode(mem, I,
515
343
                                          I->get_font_bbox(I, &I->ff,
516
343
                                                           BBox_temp, units_temp))) < 0) {
517
0
                break;
518
0
            }
519
343
            code = gs_notify_register(&pbfont1->notify_list, notify_remove_font, pbfont1);
520
343
            if (code < 0) {
521
0
                emprintf(mem,
522
0
                         "Ignoring gs_notify_register() failure for FAPI font.....");
523
0
            }
524
343
        }
525
186
        if (i == n) {
526
182
            code =
527
182
                gs_fapi_renderer_retcode(mem, I,
528
182
                                         I->get_scaled_font(I, &I->ff,
529
182
                                                            (const
530
182
                                                             gs_fapi_font_scale
531
182
                                                             *)&font_scale,
532
182
                                                            NULL,
533
182
                                                            gs_fapi_toplevel_complete));
534
182
            if (code >= 0)
535
182
                return bbox_set;        /* Full success. */
536
182
        }
537
        /* Fail, release server's font data : */
538
8
        for (i = 0; i < n; i++) {
539
4
            gs_font_type1 *pbfont1 = FDArray[i];
540
541
4
            if (pbfont1->FAPI_font_data != NULL)
542
0
                gs_fapi_release_typeface(I, &pbfont1->FAPI_font_data);
543
4
        }
544
545
4
        if (pbfont->FAPI_font_data != NULL) {
546
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
547
0
        }
548
4
        return_error(gs_error_invalidfont);
549
186
    }
550
551
    /* This was an "else", but could elicit a warning from static analysis tools
552
     * about the potential for a non-void function without a return value.
553
     */
554
101k
    code = gs_fapi_renderer_retcode(mem, I, I->get_scaled_font(I, &I->ff,
555
101k
                                                               (const
556
101k
                                                                gs_fapi_font_scale
557
101k
                                                                *)&font_scale,
558
101k
                                                               xlatmap,
559
101k
                                                               gs_fapi_toplevel_complete));
560
101k
    if (code < 0) {
561
0
        gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
562
0
        return code;
563
0
    }
564
101k
    code =
565
101k
        gs_notify_register(&pbfont->notify_list, notify_remove_font, pbfont);
566
101k
    if (code < 0) {
567
0
        gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
568
0
        return code;
569
0
    }
570
571
101k
    return bbox_set;
572
101k
}
573
574
575
static int
576
outline_char(gs_memory_t *mem, gs_fapi_server *I, int import_shift_v,
577
             gs_show_enum *penum_s, struct gx_path_s *path, bool close_path)
578
2.16k
{
579
2.16k
    gs_fapi_path path_interface = path_interface_stub;
580
2.16k
    gs_fapi_outline_handler olh;
581
2.16k
    int code = 0;
582
2.16k
    gs_gstate *pgs = penum_s->pgs;
583
2.16k
    struct gx_path_s path1;
584
585
2.16k
    (void)gx_path_init_local(&path1, mem);
586
587
2.16k
    olh.fserver = I;
588
2.16k
    olh.path = &path1;
589
2.16k
    olh.x0 = pgs->ctm.tx_fixed - float2fixed(penum_s->fapi_glyph_shift.x);
590
2.16k
    olh.y0 = pgs->ctm.ty_fixed - float2fixed(penum_s->fapi_glyph_shift.y);
591
2.16k
    olh.close_path = close_path;
592
2.16k
    olh.need_close = false;
593
2.16k
    path_interface.olh = &olh;
594
2.16k
    path_interface.shift = import_shift_v;
595
2.16k
    if ((code =
596
2.16k
         gs_fapi_renderer_retcode(mem, I,
597
2.16k
                                  I->get_char_outline(I,
598
2.16k
                                                      &path_interface))) < 0
599
2.16k
        || path_interface.gs_error != 0) {
600
18
        if (path_interface.gs_error != 0) {
601
18
            code = path_interface.gs_error;
602
18
            goto done;
603
18
        }
604
0
        else {
605
0
            goto done;
606
0
        }
607
18
    }
608
2.14k
    if (olh.need_close && olh.close_path)
609
0
        if ((code = add_closepath(&path_interface)) < 0)
610
0
            goto done;
611
2.14k
    code = gx_path_copy(&path1, path);
612
2.16k
done:
613
2.16k
    code = code >= 0 || code == gs_error_undefinedresult ? 0 : code;
614
2.16k
    gx_path_free(&path1, "outline_char");
615
2.16k
    return code;
616
2.14k
}
617
618
static void
619
compute_em_scale(const gs_font_base *pbfont, gs_fapi_metrics *metrics,
620
                 double FontMatrix_div, double *em_scale_x,
621
                 double *em_scale_y)
622
6.14k
{                               /* optimize : move this stuff to FAPI_refine_font */
623
6.14k
    gs_matrix mat;
624
6.14k
    gs_matrix *m = &mat;
625
6.14k
    int rounding_x, rounding_y; /* Striking out the 'float' representation error in FontMatrix. */
626
6.14k
    double sx, sy;
627
6.14k
    gs_fapi_server *I = pbfont->FAPI;
628
629
6.14k
#if 1
630
6.14k
    I->get_fontmatrix(I, m);
631
#else
632
    /* Temporary: replace with a FAPI call to check *if* the library needs a replacement matrix */
633
    memset(m, 0x00, sizeof(gs_matrix));
634
    m->xx = m->yy = 1.0;
635
#endif
636
637
6.14k
    if (m->xx == 0 && m->xy == 0 && m->yx == 0 && m->yy == 0)
638
0
        m = &pbfont->base->FontMatrix;
639
6.14k
    sx = hypot(m->xx, m->xy) * metrics->em_x / FontMatrix_div;
640
6.14k
    sy = hypot(m->yx, m->yy) * metrics->em_y / FontMatrix_div;
641
6.14k
    rounding_x = (int)(0x00800000 / sx);
642
6.14k
    rounding_y = (int)(0x00800000 / sy);
643
6.14k
    *em_scale_x = (int)(sx * rounding_x + 0.5) / (double)rounding_x;
644
6.14k
    *em_scale_y = (int)(sy * rounding_y + 0.5) / (double)rounding_y;
645
6.14k
}
646
647
static int
648
fapi_copy_mono(gx_device *dev1, gs_fapi_raster *rast, int dx, int dy)
649
3.01k
{
650
3.01k
    int line_step = bitmap_raster(rast->width), code;
651
652
3.01k
    if (rast->line_step >= line_step) {
653
11
        return dev_proc(dev1, copy_mono) (dev1, rast->p, 0, rast->line_step,
654
11
                                          0, dx, dy, rast->width,
655
11
                                          rast->height, 0, 1);
656
11
    }
657
3.00k
    else {                      /* bitmap data needs to be aligned, make the aligned copy : */
658
3.00k
        byte *p = gs_alloc_byte_array(dev1->memory, rast->height, line_step,
659
3.00k
                                      "fapi_copy_mono");
660
3.00k
        byte *q = p, *r = rast->p, *pe;
661
662
3.00k
        if (p == NULL)
663
0
            return_error(gs_error_VMerror);
664
3.00k
        pe = p + rast->height * line_step;
665
11.7k
        for (; q < pe; q += line_step, r += rast->line_step) {
666
8.75k
            memcpy(q, r, rast->line_step);
667
8.75k
            memset(q + rast->line_step, 0, line_step - rast->line_step);
668
8.75k
        }
669
3.00k
        code =
670
3.00k
            dev_proc(dev1, copy_mono) (dev1, p, 0, line_step, 0, dx, dy,
671
3.00k
                                       rast->width, rast->height, 0, 1);
672
3.00k
        gs_free_object(dev1->memory, p, "fapi_copy_mono");
673
3.00k
        return code;
674
3.00k
    }
675
3.01k
}
676
677
/*
678
 * For PCL/PXL pseudo-bolding, we have to "smear" a bitmap horizontally and
679
 * vertically by ORing together a rectangle of bits below and to the left of
680
 * each output bit.  We do this separately for horizontal and vertical
681
 * smearing.  Eventually, we will replace the current procedure, which takes
682
 * time proportional to W * H * (N + log2(N)), with one that is only
683
 * proportional to N (but takes W * N additional buffer space).
684
 */
685
686
/* Allocate the line buffer for bolding.  We need 2 + bold scan lines. */
687
static byte *
688
alloc_bold_lines(gs_memory_t *mem, uint width, int bold, client_name_t cname)
689
0
{
690
0
    return gs_alloc_byte_array(mem, 2 + bold, bitmap_raster(width + bold), cname);
691
0
}
692
693
/* Merge one (aligned) scan line into another, for vertical smearing. */
694
void
695
gx_fapi_bits_merge(byte *dest, const byte *src, uint nbytes)
696
0
{
697
0
        long *dp = (long *)dest;
698
0
        const long *sp = (const long *)src;
699
0
        uint n = (nbytes + sizeof(long) - 1) >> ARCH_LOG2_SIZEOF_LONG;
700
701
0
        for ( ; n >= 4; sp += 4, dp += 4, n -= 4 ) {
702
0
            dp[0] |= sp[0];
703
0
            dp[1] |= sp[1];
704
0
            dp[2] |= sp[2];
705
0
            dp[3] |= sp[3];
706
0
        }
707
0
        for ( ; n; ++sp, ++dp, --n ) {
708
0
            *dp |= *sp;
709
0
        }
710
0
}
711
712
/* Smear a scan line horizontally.  Note that the output is wider than */
713
/* the input by the amount of bolding (smear_width). */
714
void
715
gx_fapi_bits_smear_horizontally(byte *dest, const byte *src, uint width, uint smear_width)
716
0
{
717
0
        uint32_t bits_on = 0;
718
0
        const byte *sp = src;
719
0
        uint sbyte = *sp;
720
0
        byte *dp = dest;
721
0
        uint dbyte = sbyte;
722
0
        uint sdmask = 0x80;
723
0
        const byte *zp = src;
724
0
        uint zmask = 0x80;
725
0
        uint i = 0;
726
0
        uint stop;
727
728
        /* Process the first smear_width bits. */
729
0
        stop = min(smear_width, width);
730
731
0
        for ( ; i < stop; ++i ) {
732
0
            if ( sbyte & sdmask ) {
733
0
              bits_on++;
734
0
            }
735
0
            else if ( bits_on ) {
736
0
              dbyte |= sdmask;
737
0
            }
738
0
            if ( (sdmask >>= 1) == 0 ) {
739
0
                sdmask = 0x80;
740
0
                *dp++ = dbyte;
741
0
                dbyte = sbyte = *++sp;
742
0
            }
743
0
        }
744
745
        /* Process all but the last smear_width bits. */
746
0
        for ( ; i < width; ++i ) {
747
0
            if ( sbyte & sdmask ) {
748
                /* In practice, bits_on should never overflow,
749
                   but if it doesn, handle it gracefully
750
                 */
751
0
                bits_on = (uint32_t)(((uint64_t)bits_on + 1) & 0xffffffff);
752
0
            }
753
0
            else if ( bits_on ) {
754
0
                dbyte |= sdmask;
755
0
            }
756
0
            if ( *zp & zmask && bits_on > 0) {
757
0
                --bits_on;
758
0
            }
759
0
            if ( (sdmask >>= 1) == 0 ) {
760
0
                sdmask = 0x80;
761
0
                *dp++ = dbyte;
762
0
on:             switch ( (dbyte = sbyte = *++sp) ) {
763
0
                  case 0xff:
764
0
                    if ( width - i <= 8 )
765
0
                        break;
766
0
                    *dp++ = 0xff;
767
0
                    bits_on += 8 - byte_count_bits[(*zp & (zmask - 1)) + (zp[1] & -(int)zmask)];
768
0
                    ++zp;
769
0
                    i += 8;
770
0
                    goto on;
771
0
                  case 0:
772
0
                    if ( bits_on || width - i <= 8 )
773
0
                      break;
774
0
                    *dp++ = 0;
775
                    /* We know there can't be any bits to be zeroed, */
776
                    /* because bits_on can't go negative. */
777
0
                    ++zp;
778
0
                    i += 8;
779
0
                    goto on;
780
0
                  default:
781
0
                    ;
782
0
                }
783
0
            }
784
0
            if ( (zmask >>= 1) == 0 ) {
785
0
              zmask = 0x80;
786
0
              ++zp;
787
0
            }
788
0
        }
789
790
        /* Process the last smear_width bits. */
791
        /****** WRONG IF width < smear_width ******/
792
0
        stop = width + smear_width;
793
794
0
        for ( ; i < stop; ++i ) {
795
0
            if ( bits_on ) {
796
0
                dbyte |= sdmask;
797
0
            }
798
0
            if ( (sdmask >>= 1) == 0 ) {
799
0
                sdmask = 0x80;
800
0
                *dp++ = dbyte;
801
0
                dbyte = 0;
802
0
            }
803
0
            if ( *zp & zmask && bits_on > 0) {
804
0
                --bits_on;
805
0
            }
806
0
            if ( (zmask >>= 1) == 0 ) {
807
0
                zmask = 0x80;
808
0
                ++zp;
809
0
            }
810
0
        }
811
812
0
        if ( sdmask != 0x80 ) {
813
0
          *dp = dbyte;
814
0
        }
815
0
}
816
817
static const int frac_pixel_shift = 4;
818
819
/* NOTE: fapi_image_uncached_glyph() doesn't check various paramters: it assumes fapi_finish_render_aux()
820
 * has done so: if it gets called from another function, the function must either do all the parameter
821
 * validation, or fapi_image_uncached_glyph() must be changed to include the validation.
822
 */
823
static int
824
fapi_image_uncached_glyph(gs_font *pfont, gs_gstate *pgs, gs_show_enum *penum,
825
                          gs_fapi_raster *rast, const int import_shift_v)
826
661
{
827
661
    gx_device *dev = penum->dev;
828
661
    gs_gstate *penum_pgs = (gs_gstate *) penum->pgs;
829
661
    int code;
830
661
    const gx_clip_path *pcpath = pgs->clip_path;
831
661
    const gx_drawing_color *pdcolor = gs_currentdevicecolor_inline(penum->pgs);
832
661
    int rast_orig_x = rast->orig_x;
833
661
    int rast_orig_y = -rast->orig_y;
834
661
    gs_font_base *pbfont = (gs_font_base *)pfont;
835
661
    gs_fapi_server *I = pbfont->FAPI;
836
837
661
    extern_st(st_gs_show_enum);
838
839
661
    byte *r = rast->p;
840
661
    byte *src, *dst;
841
661
    int h, padbytes, cpbytes, dstr = bitmap_raster(rast->width);
842
661
    int sstr = rast->line_step;
843
844
661
    double dx = penum_pgs->ctm.tx + (double)rast_orig_x / (1 << frac_pixel_shift) + 0.5;
845
661
    double dy = penum_pgs->ctm.ty + (double)rast_orig_y / (1 << frac_pixel_shift) + 0.5;
846
847
    /* we can only safely use the gx_image_fill_masked() "shortcut" if we're drawing
848
     * a "simple" colour, rather than a pattern.
849
     */
850
661
    if (gs_color_writes_pure(penum_pgs) && I->ff.embolden == 0.0) {
851
661
        if (dstr != sstr) {
852
853
            /* If the stride of the bitmap we've got doesn't match what the rest
854
             * of the Ghostscript world expects, make one that does.
855
             * Ghostscript aligns bitmap raster memory in a platform specific
856
             * manner, so see gxbitmap.h for details.
857
             *
858
             * Ideally the padding bytes wouldn't matter, but currently the
859
             * clist code ends up compressing it using bitmap compression. To
860
             * ensure consistency across runs (and to get the best possible
861
             * compression ratios) we therefore set such bytes to zero. It would
862
             * be nicer if this was fixed in future.
863
             */
864
582
            r = gs_alloc_bytes(penum->memory, (size_t)dstr * rast->height,
865
582
                               "fapi_finish_render_aux");
866
582
            if (!r) {
867
0
                return_error(gs_error_VMerror);
868
0
            }
869
870
582
            cpbytes = sstr < dstr ? sstr : dstr;
871
582
            padbytes = dstr - cpbytes;
872
582
            h = rast->height;
873
582
            src = rast->p;
874
582
            dst = r;
875
582
            if (padbytes > 0) {
876
28.3k
                while (h-- > 0) {
877
27.7k
                    memcpy(dst, src, cpbytes);
878
27.7k
                    memset(dst + cpbytes, 0, padbytes);
879
27.7k
                    src += sstr;
880
27.7k
                    dst += dstr;
881
27.7k
                }
882
582
            }
883
0
            else {
884
0
                while (h-- > 0) {
885
0
                    memcpy(dst, src, cpbytes);
886
0
                    src += sstr;
887
0
                    dst += dstr;
888
0
                }
889
0
            }
890
582
        }
891
892
661
        if (gs_object_type(penum->memory, penum) == &st_gs_show_enum) {
893
661
            dx += penum->fapi_glyph_shift.x;
894
661
            dy += penum->fapi_glyph_shift.y;
895
661
        }
896
        /* Processing an image object operation, but this may be for a text object */
897
661
        ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
898
661
        code = gx_set_dev_color(pgs);
899
661
        if (code != 0)
900
0
            return code;
901
661
        code = gs_gstate_color_load(pgs);
902
661
        if (code < 0)
903
0
            return code;
904
905
661
        code = gx_image_fill_masked(dev, r, 0, dstr, gx_no_bitmap_id,
906
661
                                    (int)dx, (int)dy,
907
661
                                    rast->width, rast->height,
908
661
                                    pdcolor, 1, rop3_default, pcpath);
909
661
        if (rast->p != r) {
910
582
            gs_free_object(penum->memory, r, "fapi_finish_render_aux");
911
582
        }
912
661
    }
913
0
    else {
914
0
        gs_memory_t *mem = penum->memory->non_gc_memory;
915
0
        gs_image_enum *pie;
916
0
        gs_image_t image;
917
0
        int iy, nbytes;
918
0
        uint used;
919
0
        int code1;
920
0
        int w, h;
921
0
        int x = (int)dx;
922
0
        int y = (int)dy;
923
0
        uint bold = 0;
924
0
        byte *bold_lines = NULL;
925
0
        byte *line = NULL;
926
0
        int ascent = 0;
927
928
0
        pie = gs_image_enum_alloc(mem, "image_char(image_enum)");
929
0
        if (!pie) {
930
0
            return_error(gs_error_VMerror);
931
0
        }
932
933
0
        w = rast->width;
934
0
        h = rast->height;
935
0
        if (I->ff.embolden != 0.0) {
936
0
            bold = (uint)(2 * h * I->ff.embolden + 0.5);
937
0
            ascent += bold;
938
0
            bold_lines = alloc_bold_lines(pgs->memory, w, bold, "fapi_image_uncached_glyph(bold_line)");
939
0
            if (bold_lines == NULL) {
940
0
                code = gs_note_error(gs_error_VMerror);
941
0
                return(code);
942
0
            }
943
0
            line = gs_alloc_byte_array(pgs->memory, 1, bitmap_raster(w + bold) + 1, "fapi_copy_mono");
944
0
            if (line == 0) {
945
0
                gs_free_object(pgs->memory, bold_lines, "fapi_image_uncached_glyph(bold_lines)");
946
0
                code = gs_note_error(gs_error_VMerror);
947
0
                return(code);
948
0
            }
949
0
        }
950
951
        /* Make a matrix that will place the image */
952
        /* at (x,y) with no transformation. */
953
0
        gs_image_t_init_mask(&image, true);
954
0
        gs_make_translation((double) - x, (double) (- y + ascent), &image.ImageMatrix);
955
0
        gs_matrix_multiply(&ctm_only(penum_pgs), &image.ImageMatrix, &image.ImageMatrix);
956
0
        image.Width = w + bold;
957
0
        image.Height = h + bold;
958
0
        image.adjust = false;
959
0
        code = gs_image_init(pie, &image, false, true, penum_pgs);
960
0
        nbytes = (rast->width + 7) >> 3;
961
962
0
        switch (code) {
963
0
            case 1:            /* empty image */
964
0
                code = 0;
965
0
            default:
966
0
                break;
967
0
            case 0:
968
0
                if (bold == 0) {
969
0
                    for (iy = 0; iy < h && code >= 0; iy++, r += sstr) {
970
0
                        code = gs_image_next(pie, r, nbytes, &used);
971
0
                    }
972
0
                }
973
0
                else {
974
0
                    uint dest_raster = bitmap_raster(image.Width);
975
0
                    uint dest_bytes = (image.Width + 7) >> 3;
976
0
                    int n1 = bold + 1;
977
0
#define merged_line(i) (bold_lines + ((i) % n1 + 1) * dest_raster)
978
979
0
                    for ( y = 0; y < image.Height; y++ ) {
980
0
                        int y0 = (y < bold ? 0 : y - bold);
981
0
                        int y1 = min(y + 1, rast->height);
982
0
                        int kmask;
983
0
                        bool first = true;
984
985
0
                        if ( y < rast->height ) {
986
0
                            memcpy(line, r + y * rast->line_step, rast->line_step);
987
0
                            memset(line + rast->line_step, 0x00, (dest_raster + 1) -  rast->line_step);
988
989
0
                            gx_fapi_bits_smear_horizontally(merged_line(y), line, rast->width, bold);
990
                            /* Now re-establish the invariant -- see below. */
991
0
                            kmask = 1;
992
993
0
                            for ( ; (y & kmask) == kmask && y - kmask >= y0;
994
0
                                  kmask = (kmask << 1) + 1) {
995
996
0
                                gx_fapi_bits_merge(merged_line(y - kmask), merged_line(y - (kmask >> 1)), dest_bytes);
997
0
                            }
998
0
                        }
999
1000
                       /*
1001
                        * As of this point in the loop, we maintain the following
1002
                        * invariant to cache partial merges of groups of lines: for
1003
                        * each Y, y0 <= Y < y1, let K be the maximum k such that Y
1004
                        * mod 2^k = 0 and Y + 2^k < y1; then merged_line(Y) holds
1005
                        * the union of horizontally smeared source lines Y through
1006
                        * Y + 2^k - 1.  The idea behind this is similar to the idea
1007
                        * of quicksort.
1008
                        */
1009
1010
                        /* Now construct the output line. */
1011
0
                        first = true;
1012
1013
0
                        for ( iy = y1 - 1; iy >= y0; --iy ) {
1014
0
                          kmask = 1;
1015
1016
0
                          while ( (iy & kmask) == kmask && iy - kmask >= y0 )
1017
0
                            iy -= kmask, kmask <<= 1;
1018
0
                          if ( first ) {
1019
0
                            memcpy(bold_lines, merged_line(iy), dest_bytes);
1020
0
                            first = false;
1021
0
                          }
1022
0
                          else
1023
0
                            gx_fapi_bits_merge(bold_lines, merged_line(iy), dest_bytes);
1024
0
                        }
1025
0
                        code = gs_image_next(pie, bold_lines, dest_bytes, &used);
1026
0
                    }
1027
0
                }
1028
0
#undef merged_line
1029
0
        }
1030
1031
0
        if (bold_lines)
1032
0
            gs_free_object(pgs->memory, bold_lines, "fapi_image_uncached_glyph(bold_lines)");
1033
1034
0
        if (line)
1035
0
            gs_free_object(pgs->memory, line, "fapi_image_uncached_glyph(line)");
1036
1037
0
        code1 = gs_image_cleanup_and_free_enum(pie, penum_pgs);
1038
0
        if (code >= 0 && code1 < 0)
1039
0
            code = code1;
1040
0
    }
1041
661
    return (code);
1042
661
}
1043
1044
int
1045
gs_fapi_finish_render(gs_font *pfont, gs_gstate *pgs, gs_text_enum_t *penum, gs_fapi_server *I)
1046
5.85k
{
1047
5.85k
    gs_show_enum *penum_s = (gs_show_enum *) penum;
1048
5.85k
    gs_gstate *penum_pgs;
1049
5.85k
    gx_device *dev1;
1050
5.85k
    const int import_shift_v = _fixed_shift - 32;       /* we always 32.32 values for the outline interface now */
1051
5.85k
    gs_fapi_raster rast;
1052
5.85k
    int code;
1053
5.85k
    gs_memory_t *mem = pfont->memory;
1054
5.85k
    gs_font_base *pbfont = (gs_font_base *)pfont;
1055
1056
5.85k
    if (penum == NULL)
1057
0
        return_error(gs_error_undefined);
1058
1059
5.85k
    penum_pgs = penum_s->pgs;
1060
1061
5.85k
    dev1 = gs_currentdevice_inline(penum_pgs);  /* Possibly changed by zchar_set_cache. */
1062
1063
    /* Even for "non-marking" text operations (for example, stringwidth) we are expected
1064
     * to have a glyph bitmap for the cache, if we're using the cache. For the
1065
     * non-cacheing, non-marking cases, we must not draw the glyph.
1066
     */
1067
5.85k
    if (pgs->in_charpath && !SHOW_IS(penum, TEXT_DO_NONE)) {
1068
13
        gs_point pt;
1069
1070
13
        if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1071
0
            return code;
1072
1073
13
        if ((code =
1074
13
             outline_char(mem, I, import_shift_v, penum_s, penum_pgs->path,
1075
13
                          !pbfont->PaintType)) < 0) {
1076
0
            return code;
1077
0
        }
1078
1079
13
        if ((code =
1080
13
             gx_path_add_char_path(penum_pgs->show_gstate->path,
1081
13
                                   penum_pgs->path,
1082
13
                                   penum_pgs->in_charpath)) < 0) {
1083
0
            return code;
1084
0
        }
1085
1086
13
    }
1087
5.84k
    else {
1088
5.84k
        int code;
1089
5.84k
        memset(&rast, 0x00, sizeof(rast));
1090
1091
5.84k
        if ((code = I->get_char_raster(I, &rast)) < 0 && code != gs_error_unregistered)
1092
0
            return code;
1093
1094
5.84k
        if (!SHOW_IS(penum, TEXT_DO_NONE) && I->use_outline) {
1095
            /* The server provides an outline instead the raster. */
1096
2.15k
            gs_point pt;
1097
1098
            /* This mimics code which is used below in the case where I->Use_outline is set.
1099
             * This is usually caused by setting -dTextAlphaBits, and will result in 'undefinedresult'
1100
             * errors. We want the code to work the same regardless off the setting of -dTextAlphaBits
1101
             * and it seems the simplest way to provoke the same error is to do the same steps....
1102
             * Note that we do not actually ever use the returned value.
1103
             */
1104
2.15k
            if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1105
0
                return code;
1106
1107
2.15k
            if ((code =
1108
2.15k
                 outline_char(mem, I, import_shift_v, penum_s,
1109
2.15k
                              penum_pgs->path, !pbfont->PaintType)) < 0)
1110
0
                return code;
1111
2.15k
            if ((code =
1112
2.15k
                 gs_gstate_setflat((gs_gstate *) penum_pgs,
1113
2.15k
                                   gs_char_flatness(penum_pgs->show_gstate, 1.0))) < 0)
1114
0
                return code;
1115
2.15k
            if (pbfont->PaintType) {
1116
0
                float lw = gs_currentlinewidth(penum_pgs);
1117
1118
0
                gs_setlinewidth(penum_pgs, pbfont->StrokeWidth);
1119
0
                code = gs_stroke(penum_pgs);
1120
0
                gs_setlinewidth(penum_pgs, lw);
1121
0
                if (code < 0)
1122
0
                    return code;
1123
0
            }
1124
2.15k
            else {
1125
2.15k
                gs_in_cache_device_t in_cachedevice =
1126
2.15k
                    penum_pgs->in_cachedevice;
1127
1128
2.15k
                penum_pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1129
1130
2.15k
                penum_pgs->fill_adjust.x = penum_pgs->fill_adjust.y = 0;
1131
1132
2.15k
                code = gs_fill(penum_pgs);
1133
1134
2.15k
                penum_pgs->in_cachedevice = in_cachedevice;
1135
1136
2.15k
                if (code < 0)
1137
0
                    return code;
1138
2.15k
            }
1139
2.15k
            if ((code = gs_moveto(penum_pgs, pt.x, pt.y)) < 0)
1140
0
                return code;
1141
2.15k
        }
1142
3.68k
        else {
1143
3.68k
            int rast_orig_x = rast.orig_x;
1144
3.68k
            int rast_orig_y = -rast.orig_y;
1145
3.68k
            gs_point pt;
1146
1147
            /* This mimics code which is used above in the case where I->Use_outline is set.
1148
             * This is usually caused by setting -dTextAlphaBits, and will result in 'undefinedresult'
1149
             * errors. We want the code to work the same regardless off the setting of -dTextAlphaBits
1150
             * and it seems the simplest way to provoke the same error is to do the same steps....
1151
             * Note that we do not actually ever use the returned value.
1152
             */
1153
3.68k
            if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1154
0
                return code;
1155
1156
3.68k
            if (penum_pgs->in_cachedevice == CACHE_DEVICE_CACHING) {    /* Using GS cache */
1157
                /*  GS and renderer may transform coordinates few differently.
1158
                   The best way is to make set_cache_device to take the renderer's bitmap metrics immediately,
1159
                   but we need to account CDevProc, which may truncate the bitmap.
1160
                   Perhaps GS overestimates the bitmap size,
1161
                   so now we only add a compensating shift - the dx and dy.
1162
                 */
1163
3.02k
                if (rast.width != 0) {
1164
3.01k
                    int shift_rd = _fixed_shift - frac_pixel_shift;
1165
3.01k
                    int rounding = 1 << (frac_pixel_shift - 1);
1166
3.01k
                    int dx =
1167
3.01k
                        arith_rshift_slow((penum_pgs->
1168
3.01k
                                           ctm.tx_fixed >> shift_rd) +
1169
3.01k
                                          rast_orig_x + rounding,
1170
3.01k
                                          frac_pixel_shift);
1171
3.01k
                    int dy =
1172
3.01k
                        arith_rshift_slow((penum_pgs->
1173
3.01k
                                           ctm.ty_fixed >> shift_rd) +
1174
3.01k
                                          rast_orig_y + rounding,
1175
3.01k
                                          frac_pixel_shift);
1176
1177
3.01k
                    if (dx + rast.left_indent < 0
1178
3.01k
                        || dx + rast.left_indent + rast.black_width >
1179
3.01k
                        dev1->width) {
1180
#ifdef DEBUG
1181
                        if (gs_debug_c('m')) {
1182
                            emprintf2(dev1->memory,
1183
                                      "Warning : Cropping a FAPI glyph while caching : dx=%d,%d.\n",
1184
                                      dx + rast.left_indent,
1185
                                      dx + rast.left_indent +
1186
                                      rast.black_width - dev1->width);
1187
                        }
1188
#endif
1189
0
                        if (dx + rast.left_indent < 0)
1190
0
                            dx -= dx + rast.left_indent;
1191
0
                    }
1192
3.01k
                    if (dy + rast.top_indent < 0
1193
3.01k
                        || dy + rast.top_indent + rast.black_height >
1194
3.01k
                        dev1->height) {
1195
#ifdef DEBUG
1196
                        if (gs_debug_c('m')) {
1197
                            emprintf2(dev1->memory,
1198
                                      "Warning : Cropping a FAPI glyph while caching : dx=%d,%d.\n",
1199
                                      dy + rast.top_indent,
1200
                                      dy + rast.top_indent +
1201
                                      rast.black_height - dev1->height);
1202
                        }
1203
#endif
1204
0
                        if (dy + rast.top_indent < 0)
1205
0
                            dy -= dy + rast.top_indent;
1206
0
                    }
1207
3.01k
                    if ((code = fapi_copy_mono(dev1, &rast, dx, dy)) < 0)
1208
0
                        return code;
1209
1210
3.01k
                    if (penum_s->cc != NULL) {
1211
3.01k
                        penum_s->cc->offset.x +=
1212
3.01k
                            float2fixed(penum_s->fapi_glyph_shift.x);
1213
3.01k
                        penum_s->cc->offset.y +=
1214
3.01k
                            float2fixed(penum_s->fapi_glyph_shift.y);
1215
3.01k
                    }
1216
3.01k
                }
1217
3.02k
            }
1218
661
            else if (!SHOW_IS(penum, TEXT_DO_NONE)) {   /* Not using GS cache */
1219
661
                if ((code =
1220
661
                     fapi_image_uncached_glyph(pfont, pgs, penum_s, &rast,
1221
661
                                               import_shift_v)) < 0)
1222
0
                    return code;
1223
661
            }
1224
3.68k
        }
1225
5.84k
    }
1226
1227
5.85k
    return 0;
1228
5.85k
}
1229
1230
1231
0
#define GET_U16_MSB(p) (((uint)((p)[0]) << 8) + (p)[1])
1232
0
#define GET_S16_MSB(p) (int)((GET_U16_MSB(p) ^ 0x8000) - 0x8000)
1233
1234
12.6k
#define MTX_EQ(mtx1,mtx2) (mtx1->xx == mtx2->xx && mtx1->xy == mtx2->xy && \
1235
6.22k
                           mtx1->yx == mtx2->yx && mtx1->yy == mtx2->yy)
1236
1237
int
1238
gs_fapi_do_char(gs_font *pfont, gs_gstate *pgs, gs_text_enum_t *penum, char *font_file_path,
1239
                bool bBuildGlyph, gs_string *charstring, gs_string *glyphname,
1240
                gs_char chr, gs_glyph index, int subfont)
1241
6.35k
{                               /* Stack : <font> <code|name> --> - */
1242
6.35k
    gs_show_enum *penum_s = (gs_show_enum *) penum;
1243
6.35k
    gx_device *dev = gs_currentdevice_inline(pgs);
1244
1245
    /*
1246
       fixme: the following code needs to optimize with a maintainence of scaled font objects
1247
       in graphics library and in interpreter. Now we suppose that the renderer
1248
       uses font cache, so redundant font opening isn't a big expense.
1249
     */
1250
6.35k
    gs_fapi_char_ref cr =
1251
6.35k
        { 0, {0}, 0, false, NULL, 0, 0, 0, 0, 0, gs_fapi_metrics_notdef };
1252
6.35k
    gs_font_base *pbfont = (gs_font_base *)pfont;
1253
6.35k
    const gs_matrix *ctm = &ctm_only(pgs);
1254
6.35k
    int scale;
1255
6.35k
    gs_fapi_metrics metrics;
1256
6.35k
    gs_fapi_server *I = pbfont->FAPI;
1257
1258
6.35k
    gs_string enc_char_name_string;
1259
6.35k
    bool bCID = (FAPI_ISCIDFONT(pbfont) || charstring != NULL);
1260
6.35k
    bool bIsType1GlyphData = FAPI_ISTYPE1GLYPHDATA(pbfont);
1261
6.35k
    gs_log2_scale_point log2_scale = { 0, 0 };
1262
6.35k
    int alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
1263
6.35k
    double FontMatrix_div = 1;
1264
6.35k
    bool bVertical = (gs_rootfont(pgs)->WMode != 0), bVertical0 = bVertical;
1265
6.35k
    double *sbwp, sbw[4] = { 0, 0, 0, 0 };
1266
6.35k
    double em_scale_x, em_scale_y;
1267
6.35k
    gs_rect char_bbox;
1268
6.35k
    int code;
1269
6.35k
    bool imagenow = false;
1270
6.35k
    bool align_to_pixels = gs_currentaligntopixels(pbfont->dir);
1271
6.35k
    gs_memory_t *mem = pfont->memory;
1272
6.35k
    enum
1273
6.35k
    {
1274
6.35k
        SBW_DONE,
1275
6.35k
        SBW_SCALE,
1276
6.35k
        SBW_FROM_RENDERER
1277
6.35k
    } sbw_state = SBW_SCALE;
1278
1279
6.35k
    if ( index == GS_NO_GLYPH )
1280
0
        return 0;
1281
1282
6.35k
    I->use_outline = false;
1283
6.35k
    I->transform_outline = false;
1284
1285
6.35k
    if (penum == 0)
1286
0
        return_error(gs_error_undefined);
1287
1288
6.35k
    I->use_outline =
1289
6.35k
        produce_outline_char(penum_s, pbfont, alpha_bits, &log2_scale);
1290
1291
6.35k
    if (I->use_outline) {
1292
2.09k
        I->max_bitmap = 0;
1293
2.09k
    }
1294
4.26k
    else {
1295
        /* FIX ME: It can be a very bad thing, right now, for the FAPI code to decide unilaterally to
1296
         * produce an outline, when the rest of GS expects a bitmap, so we give ourselves a
1297
         * 50% leeway on the maximum cache bitmap, just to be sure. Or the same maximum bitmap size
1298
         * used in gxchar.c
1299
         */
1300
4.26k
        I->max_bitmap =
1301
4.26k
            pbfont->dir->ccache.upper + (pbfont->dir->ccache.upper >> 1) <
1302
4.26k
            MAX_CCACHE_TEMP_BITMAP_BITS ? pbfont->dir->ccache.upper +
1303
4.26k
            (pbfont->dir->ccache.upper >> 1) : MAX_CCACHE_TEMP_BITMAP_BITS;
1304
4.26k
    }
1305
1306
6.35k
    if (pbfont->memory->gs_lib_ctx->font_dir != NULL)
1307
6.35k
        I->grid_fit = pbfont->memory->gs_lib_ctx->font_dir->grid_fit_tt;
1308
0
    else
1309
0
        I->grid_fit = pbfont->dir->grid_fit_tt;
1310
1311
    /* Compute the scale : */
1312
6.35k
    if (!SHOW_IS(penum, TEXT_DO_NONE) && !I->use_outline) {
1313
2.99k
        gs_currentcharmatrix(pgs, NULL, 1);     /* make char_tm valid */
1314
2.99k
        penum_s->fapi_log2_scale = log2_scale;
1315
2.99k
    }
1316
3.35k
    else {
1317
3.35k
        log2_scale.x = 0;
1318
3.35k
        log2_scale.y = 0;
1319
3.35k
    }
1320
1321
    /* Prepare font data
1322
     * This needs done here (earlier than it used to be) because FAPI/UFST has conflicting
1323
     * requirements in what I->get_fontmatrix() returns based on font type, so it needs to
1324
     * find the font type.
1325
     */
1326
1327
6.35k
    I->ff.memory = pbfont->memory;
1328
6.35k
    I->ff.subfont = subfont;
1329
6.35k
    I->ff.font_file_path = font_file_path;
1330
6.35k
    I->ff.client_font_data = pbfont;
1331
6.35k
    I->ff.client_font_data2 = pbfont;
1332
6.35k
    I->ff.server_font_data = pbfont->FAPI_font_data;
1333
6.35k
    I->ff.is_type1 = bIsType1GlyphData;
1334
6.35k
    I->ff.is_cid = bCID;
1335
6.35k
    I->ff.is_outline_font = pbfont->PaintType != 0;
1336
6.35k
    I->ff.metrics_only = fapi_gs_char_show_width_only(penum);
1337
1338
6.35k
    if (!I->ff.is_mtx_skipped)
1339
6.35k
        I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
1340
1341
6.35k
    I->ff.is_vertical = bVertical;
1342
6.35k
    I->ff.client_ctx_p = I->client_ctx_p;
1343
1344
6.35k
    if (recreate_multiple_master(pbfont)) {
1345
0
        if ((void *)pbfont->base == (void *)pbfont) {
1346
0
           gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
1347
0
        }
1348
0
        else {
1349
0
            pbfont->FAPI_font_data = NULL;
1350
0
            pbfont->FAPI->face.font_id = gs_no_id;
1351
0
        }
1352
0
    }
1353
1354
6.35k
   scale = 1 << I->frac_shift;
1355
6.43k
retry_oversampling:
1356
6.43k
    if (I->face.font_id != pbfont->id ||
1357
6.43k
        !MTX_EQ((&I->face.ctm), ctm) ||
1358
6.43k
        I->face.log2_scale.x != log2_scale.x ||
1359
6.43k
        I->face.log2_scale.y != log2_scale.y ||
1360
6.43k
        I->face.align_to_pixels != align_to_pixels ||
1361
6.43k
        I->face.HWResolution[0] != dev->HWResolution[0] ||
1362
6.43k
        I->face.HWResolution[1] != dev->HWResolution[1]
1363
6.43k
        ) {
1364
398
        gs_fapi_font_scale font_scale = { {1, 0, 0, 1, 0, 0}
1365
398
        , {0, 0}
1366
398
        , {1, 1}
1367
398
        , true
1368
398
        };
1369
1370
398
        gs_matrix lctm, scale_mat, scale_ctm;
1371
398
        I->face.font_id = pbfont->id;
1372
398
        I->face.log2_scale = log2_scale;
1373
398
        I->face.align_to_pixels = align_to_pixels;
1374
398
        I->face.HWResolution[0] = dev->HWResolution[0];
1375
398
        I->face.HWResolution[1] = dev->HWResolution[1];
1376
1377
398
        font_scale.subpixels[0] = 1 << log2_scale.x;
1378
398
        font_scale.subpixels[1] = 1 << log2_scale.y;
1379
398
        font_scale.align_to_pixels = align_to_pixels;
1380
1381
        /* We apply the entire transform to the glyph (that is ctm x FontMatrix)
1382
         * at render time.
1383
         */
1384
398
        lctm = *ctm;
1385
398
retry_scaling:
1386
398
        I->face.ctm = lctm;
1387
398
        memset(&scale_ctm, 0x00, sizeof(gs_matrix));
1388
398
        scale_ctm.xx = dev->HWResolution[0] / 72;
1389
398
        scale_ctm.yy = dev->HWResolution[1] / 72;
1390
1391
398
        if ((code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm)) < 0)
1392
0
            return code;
1393
1394
398
        if ((code = gs_matrix_multiply(&lctm, &scale_ctm, &scale_mat)) < 0)  /* scale_mat ==  CTM - resolution scaling */
1395
0
            return code;
1396
1397
398
        if ((code = I->get_fontmatrix(I, &scale_ctm)) < 0)
1398
0
            return code;
1399
1400
398
        if ((code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm)) < 0)
1401
0
            return code;
1402
1403
398
        if ((code = gs_matrix_multiply(&scale_mat, &scale_ctm, &scale_mat)) < 0)  /* scale_mat ==  CTM - resolution scaling - FontMatrix scaling */
1404
0
            return code;
1405
1406
398
        if (((int64_t)(scale_mat.xx * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.xx * FontMatrix_div * scale + 0.5))
1407
398
        ||  ((int64_t)(scale_mat.xy * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.xy * FontMatrix_div * scale + 0.5))
1408
398
        ||  ((int64_t)(scale_mat.yx * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.yx * FontMatrix_div * scale + 0.5))
1409
398
        ||  ((int64_t)(scale_mat.yy * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.yy * FontMatrix_div * scale + 0.5))) {
1410
            /* Overflow
1411
               If the scaling is large enough to overflow the 16.16 representation, we forcibly produce an outline
1412
               unscaled except an arbitrary "midrange" scale (chosen to avoid under/overflow issues). And
1413
               then scale the points as we create the Ghostscript path outline_char().
1414
               If the glyph is this large, we're really not worried about hinting or dropout detection etc.
1415
             */
1416
1417
0
            memset(&lctm, 0x00, sizeof(gs_matrix));
1418
0
            lctm.xx = 256.0;
1419
0
            lctm.yy = 256.0;
1420
0
            I->transform_outline = true;
1421
0
            I->use_outline = true;
1422
0
            if ((code = gs_matrix_invert((const gs_matrix *)&lctm, &scale_ctm)) < 0)
1423
0
                 return code;
1424
0
            if ((code = gs_matrix_multiply(ctm, &scale_ctm, &scale_mat)) < 0)  /* scale_mat ==  CTM - resolution scaling */
1425
0
                return code;
1426
1427
0
            I->outline_mat = scale_mat;
1428
0
            goto retry_scaling;
1429
0
        }
1430
398
        else {
1431
398
            font_scale.matrix[0] =  FAPI_ROUND_TO_FRACINT(scale_mat.xx * FontMatrix_div * scale);
1432
398
            font_scale.matrix[1] = -FAPI_ROUND_TO_FRACINT(scale_mat.xy * FontMatrix_div * scale);
1433
398
            font_scale.matrix[2] =  FAPI_ROUND_TO_FRACINT(scale_mat.yx * FontMatrix_div * scale);
1434
398
            font_scale.matrix[3] = -FAPI_ROUND_TO_FRACINT(scale_mat.yy * FontMatrix_div * scale);
1435
398
            font_scale.matrix[4] =  FAPI_ROUND_TO_FRACINT(scale_mat.tx * FontMatrix_div * scale);
1436
398
            font_scale.matrix[5] =  FAPI_ROUND_TO_FRACINT(scale_mat.ty * FontMatrix_div * scale);
1437
398
        }
1438
1439
        /* Note: the ctm mapping here is upside down. */
1440
398
        font_scale.HWResolution[0] =
1441
398
            (fracint) ((double)dev->HWResolution[0] *
1442
398
                       font_scale.subpixels[0] * scale);
1443
398
        font_scale.HWResolution[1] =
1444
398
            (fracint) ((double)dev->HWResolution[1] *
1445
398
                       font_scale.subpixels[1] * scale);
1446
1447
1448
398
        if ((hypot((double)font_scale.matrix[0], (double)font_scale.matrix[2])
1449
398
             == 0.0
1450
398
             || hypot((double)font_scale.matrix[1],
1451
398
                      (double)font_scale.matrix[3]) == 0.0)) {
1452
1453
            /* If the matrix is degenerate, force a scale to 1 unit. */
1454
0
            memset(&font_scale.matrix, 0x00, sizeof(font_scale.matrix));
1455
0
            if (!font_scale.matrix[0])
1456
0
                font_scale.matrix[0] = 1;
1457
0
            if (!font_scale.matrix[3])
1458
0
                font_scale.matrix[3] = 1;
1459
0
        }
1460
1461
398
        if ((code =
1462
398
             gs_fapi_renderer_retcode(mem, I,
1463
398
                                      I->get_scaled_font(I, &I->ff,
1464
398
                                                         &font_scale, NULL,
1465
398
                                                         gs_fapi_toplevel_prepared))) < 0) {
1466
0
            return code;
1467
0
        }
1468
398
        pbfont->FAPI_font_data = I->ff.server_font_data;    /* Save it back to GS font. */
1469
398
    }
1470
1471
6.43k
    cr.char_codes_count = 1;
1472
6.43k
    cr.char_codes[0] = index;
1473
6.43k
    cr.client_char_code = chr;
1474
6.43k
    cr.is_glyph_index = true;
1475
6.43k
    enc_char_name_string.data = NULL;
1476
6.43k
    enc_char_name_string.size = 0;
1477
1478
6.43k
    if (I->ff.get_glyphname_or_cid) {
1479
6.43k
        if ((code =
1480
6.43k
             I->ff.get_glyphname_or_cid(penum, pbfont, charstring, glyphname, index,
1481
6.43k
                                        &enc_char_name_string, font_file_path,
1482
6.43k
                                        &cr, bCID)) < 0)
1483
0
            return (code);
1484
6.43k
    }
1485
1486
    /* Compute the metrics replacement : */
1487
6.43k
    if (bCID && !bIsType1GlyphData) {
1488
911
        gs_font_cid2 *pfcid = (gs_font_cid2 *) pbfont;
1489
911
        int MetricsCount = pfcid->cidata.MetricsCount;
1490
1491
911
        if (MetricsCount > 0) {
1492
0
            const byte *data_ptr;
1493
0
            int l = I->ff.get_glyphdirectory_data(&(I->ff), cr.char_codes[0],
1494
0
                                                  &data_ptr);
1495
1496
            /* We do not need to apply the unitsPerEm scale here because
1497
             * these values are read directly from the glyph data.
1498
             */
1499
0
            if (MetricsCount == 2 && l >= 4) {
1500
0
                if (!bVertical0) {
1501
0
                    cr.sb_x = GET_S16_MSB(data_ptr + 2) * scale;
1502
0
                    cr.aw_x = GET_U16_MSB(data_ptr + 0) * scale;
1503
0
                    cr.metrics_type = gs_fapi_metrics_replace;
1504
0
                }
1505
0
            }
1506
0
            else if (l >= 8) {
1507
0
                cr.sb_y = GET_S16_MSB(data_ptr + 2) * scale;
1508
0
                cr.aw_y = GET_U16_MSB(data_ptr + 0) * scale;
1509
0
                cr.sb_x = GET_S16_MSB(data_ptr + 6) * scale;
1510
0
                cr.aw_x = GET_U16_MSB(data_ptr + 4) * scale;
1511
0
                cr.metrics_type = gs_fapi_metrics_replace;
1512
0
            }
1513
0
        }
1514
911
    }
1515
    /* Metrics in GS are scaled to a 1.0x1.0 square, as that's what Postscript
1516
     * fonts expect. But for Truetype we need the "native" units,
1517
     */
1518
6.43k
    em_scale_x = 1.0;
1519
6.43k
    if (pfont->FontType == ft_TrueType) {
1520
2.25k
        gs_font_type42 *pfont42 = (gs_font_type42 *) pfont;
1521
2.25k
        em_scale_x = pfont42->data.unitsPerEm;
1522
2.25k
    }
1523
1524
6.43k
    if (cr.metrics_type != gs_fapi_metrics_replace && bVertical) {
1525
686
        double pwv[4];
1526
1527
686
        code =
1528
686
            I->ff.fapi_get_metrics(&I->ff, &enc_char_name_string, index, pwv,
1529
686
                                   bVertical);
1530
686
        if (code < 0)
1531
0
            return code;
1532
686
        if (code == 0 /* metricsNone */ ) {
1533
686
            if (bCID && (!bIsType1GlyphData && font_file_path)) {
1534
0
                cr.sb_x = (fracint)(fapi_round( (sbw[2] / 2)         * scale) * em_scale_x);
1535
0
                cr.sb_y = (fracint)(fapi_round( pbfont->FontBBox.q.y * scale) * em_scale_x);
1536
0
                cr.aw_y = (fracint)(fapi_round(-pbfont->FontBBox.q.x * scale) * em_scale_x);    /* Sic ! */
1537
0
                cr.metrics_scale = 1;
1538
0
                cr.metrics_type = gs_fapi_metrics_replace;
1539
0
                sbw[0] = sbw[2] / 2;
1540
0
                sbw[1] = pbfont->FontBBox.q.y;
1541
0
                sbw[2] = 0;
1542
0
                sbw[3] = -pbfont->FontBBox.q.x; /* Sic ! */
1543
0
                sbw_state = SBW_DONE;
1544
0
            }
1545
686
            else {
1546
686
                bVertical = false;
1547
686
            }
1548
686
        }
1549
0
        else {
1550
0
            cr.sb_x = (fracint)(fapi_round(pwv[2] * scale) * em_scale_x);
1551
0
            cr.sb_y = (fracint)(fapi_round(pwv[3] * scale) * em_scale_x);
1552
0
            cr.aw_x = (fracint)(fapi_round(pwv[0] * scale) * em_scale_x);
1553
0
            cr.aw_y = (fracint)(fapi_round(pwv[1] * scale) * em_scale_x);
1554
0
            cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
1555
0
            cr.metrics_type = (code == 2 /* metricsSideBearingAndWidth */ ? gs_fapi_metrics_replace
1556
0
                               : gs_fapi_metrics_replace_width);
1557
0
            sbw[0] = pwv[2];
1558
0
            sbw[1] = pwv[3];
1559
0
            sbw[2] = pwv[0];
1560
0
            sbw[3] = pwv[1];
1561
0
            sbw_state = SBW_DONE;
1562
0
        }
1563
686
    }
1564
6.43k
    if (cr.metrics_type == gs_fapi_metrics_notdef && !bVertical) {
1565
6.42k
        code =
1566
6.42k
            I->ff.fapi_get_metrics(&I->ff, &enc_char_name_string, (int)index, sbw,
1567
6.42k
                                   bVertical);
1568
6.42k
        if (code < 0)
1569
0
            return code;
1570
6.42k
        if (code == 0 /* metricsNone */ ) {
1571
6.42k
            sbw_state = SBW_FROM_RENDERER;
1572
6.42k
            if (pbfont->FontType == 2) {
1573
1.61k
                gs_font_type1 *pfont1 = (gs_font_type1 *) pbfont;
1574
1575
1.61k
                cr.aw_x =
1576
1.61k
                    export_shift(pfont1->data.defaultWidthX,
1577
1.61k
                                 _fixed_shift - I->frac_shift);
1578
1.61k
                cr.metrics_scale = 1000;
1579
1.61k
                cr.metrics_type = gs_fapi_metrics_add;
1580
1.61k
            }
1581
6.42k
        }
1582
0
        else {
1583
0
            cr.sb_x = fapi_round(sbw[0] * scale * em_scale_x);
1584
0
            cr.sb_y = fapi_round(sbw[1] * scale * em_scale_x);
1585
0
            cr.aw_x = fapi_round(sbw[2] * scale * em_scale_x);
1586
0
            cr.aw_y = fapi_round(sbw[3] * scale * em_scale_x);
1587
0
            cr.metrics_scale = (bIsType1GlyphData ? 1000 : 1);
1588
0
            cr.metrics_type = (code == 2 /* metricsSideBearingAndWidth */ ? gs_fapi_metrics_replace
1589
0
                               : gs_fapi_metrics_replace_width);
1590
0
            sbw_state = SBW_DONE;
1591
0
        }
1592
6.42k
    }
1593
6.43k
    memset(&metrics, 0x00, sizeof(metrics));
1594
    /* Take metrics from font : */
1595
6.43k
    if (I->ff.metrics_only) {
1596
291
        code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
1597
291
    }
1598
6.13k
    else if (I->use_outline) {
1599
2.16k
        code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
1600
2.16k
    }
1601
3.97k
    else {
1602
3.97k
        code = I->get_char_raster_metrics(I, &I->ff, &cr, &metrics);
1603
        /* A VMerror could be a real out of memory, or the glyph being too big for a bitmap
1604
         * so it's worth retrying as an outline glyph
1605
         */
1606
3.97k
        if (code == gs_error_VMerror) {
1607
75
            I->use_outline = true;
1608
75
            goto retry_oversampling;
1609
75
        }
1610
3.89k
        if (code == gs_error_limitcheck) {
1611
0
            if (log2_scale.x > 0 || log2_scale.y > 0) {
1612
0
                penum_s->fapi_log2_scale.x = log2_scale.x =
1613
0
                    penum_s->fapi_log2_scale.y = log2_scale.y = 0;
1614
0
                I->release_char_data(I);
1615
0
                goto retry_oversampling;
1616
0
            }
1617
0
            code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
1618
0
        }
1619
3.89k
    }
1620
1621
    /* This handles the situation where a charstring has been replaced with a PS procedure.
1622
     * against the rules, but not *that* rare.
1623
     * It's also something that GS does internally to simulate font styles.
1624
     */
1625
6.35k
    if (code > 0) {
1626
0
        return (gs_error_unregistered);
1627
0
    }
1628
1629
6.35k
    if ((code = gs_fapi_renderer_retcode(mem, I, code)) < 0)
1630
211
        return code;
1631
1632
6.14k
    compute_em_scale(pbfont, &metrics, FontMatrix_div, &em_scale_x,
1633
6.14k
                     &em_scale_y);
1634
6.14k
    char_bbox.p.x = metrics.bbox_x0 / em_scale_x;
1635
6.14k
    char_bbox.p.y = metrics.bbox_y0 / em_scale_y;
1636
6.14k
    char_bbox.q.x = metrics.bbox_x1 / em_scale_x;
1637
6.14k
    char_bbox.q.y = metrics.bbox_y1 / em_scale_y;
1638
1639
    /* We must use the FontBBox, but it seems some buggy fonts have glyphs which extend outside the
1640
     * FontBBox, so we have to do this....
1641
     */
1642
6.14k
    if (pbfont->FontType != ft_MicroType && !bCID
1643
6.14k
        && pbfont->FontBBox.q.x > pbfont->FontBBox.p.x
1644
6.14k
        && pbfont->FontBBox.q.y > pbfont->FontBBox.p.y) {
1645
4.21k
        char_bbox.p.x = min(char_bbox.p.x, pbfont->FontBBox.p.x);
1646
4.21k
        char_bbox.p.y = min(char_bbox.p.y, pbfont->FontBBox.p.y);
1647
4.21k
        char_bbox.q.x = max(char_bbox.q.x, pbfont->FontBBox.q.x);
1648
4.21k
        char_bbox.q.y = max(char_bbox.q.y, pbfont->FontBBox.q.y);
1649
4.21k
    }
1650
1651
6.14k
    if (pbfont->PaintType != 0) {
1652
0
        float w = pbfont->StrokeWidth / 2;
1653
1654
0
        char_bbox.p.x -= w;
1655
0
        char_bbox.p.y -= w;
1656
0
        char_bbox.q.x += w;
1657
0
        char_bbox.q.y += w;
1658
0
    }
1659
6.14k
    penum_s->fapi_glyph_shift.x = penum_s->fapi_glyph_shift.y = 0;
1660
6.14k
    if (sbw_state == SBW_FROM_RENDERER) {
1661
6.14k
        int can_replace_metrics;
1662
1663
6.14k
        if ((code =
1664
6.14k
             gs_fapi_renderer_retcode(mem, I,
1665
6.14k
                                      I->can_replace_metrics(I, &I->ff, &cr,
1666
6.14k
                                                             &can_replace_metrics)))
1667
6.14k
            < 0)
1668
0
            return code;
1669
1670
6.14k
        sbw[2] = metrics.escapement / em_scale_x;
1671
6.14k
        sbw[3] = metrics.v_escapement / em_scale_y;
1672
6.14k
        if (pbfont->FontType == 2 && !can_replace_metrics) {
1673
0
            gs_font_type1 *pfont1 = (gs_font_type1 *) pbfont;
1674
1675
0
            sbw[2] += fixed2float(pfont1->data.nominalWidthX);
1676
0
        }
1677
6.14k
    }
1678
0
    else if (sbw_state == SBW_SCALE) {
1679
0
        sbw[0] = (double)cr.sb_x / scale / em_scale_x;
1680
0
        sbw[1] = (double)cr.sb_y / scale / em_scale_y;
1681
0
        sbw[2] = (double)cr.aw_x / scale / em_scale_x;
1682
0
        sbw[3] = (double)cr.aw_y / scale / em_scale_y;
1683
0
    }
1684
1685
    /* Setup cache and render : */
1686
6.14k
    if (cr.metrics_type == gs_fapi_metrics_replace) {
1687
        /*
1688
         * Here we don't take care of replaced advance width
1689
         * because gs_text_setcachedevice handles it.
1690
         */
1691
0
        int can_replace_metrics;
1692
1693
0
        if ((code =
1694
0
             gs_fapi_renderer_retcode(mem, I,
1695
0
                                      I->can_replace_metrics(I, &I->ff, &cr,
1696
0
                                                             &can_replace_metrics)))
1697
0
            < 0)
1698
0
            return code;
1699
0
        if (!can_replace_metrics) {
1700
            /*
1701
             * The renderer should replace the lsb, but it can't.
1702
             * To work around we compute a displacement in integral pixels
1703
             * and later shift the bitmap to it. The raster will be inprecise
1704
             * with non-integral pixels shift.
1705
             */
1706
0
            char_bbox.q.x -= char_bbox.p.x;
1707
0
            char_bbox.p.x = 0;
1708
0
            gs_distance_transform((metrics.bbox_x0 / em_scale_x - sbw[0]),
1709
0
                                  0, ctm, &penum_s->fapi_glyph_shift);
1710
0
            penum_s->fapi_glyph_shift.x *= 1 << log2_scale.x;
1711
0
            penum_s->fapi_glyph_shift.y *= 1 << log2_scale.y;
1712
0
        }
1713
0
    }
1714
1715
    /*
1716
     * We assume that if bMetricsFromGlyphDirectory is true,
1717
     * the font does not specify Metrics[2] and/or CDevProc
1718
     * If someday we meet a font contradicting this assumption,
1719
     * zchar_set_cache to be improved with additional flag,
1720
     * to ignore Metrics[2] and CDevProc.
1721
     *
1722
     * Note that for best quality the result of CDevProc
1723
     * to be passed to I->get_char_raster_metrics, because
1724
     * both raster and metrics depend on replaced lsb.
1725
     * Perhaps in many cases the metrics from font is
1726
     * used as an argument for CDevProc. Only way to resolve
1727
     * is to call I->get_char_raster_metrics twice (before
1728
     * and after CDevProc), or better to split it into
1729
     * smaller functions. Unfortunately UFST cannot retrieve metrics
1730
     * quickly and separately from raster. Only way to resolve is
1731
     * to devide the replaced lsb into 2 parts, which correspond to
1732
     * integral and fractinal pixels, then pass the fractional shift
1733
     * to renderer and apply the integer shift after it.
1734
     *
1735
     * Besides that, we are not sure what to do if a font
1736
     * contains both Metrics[2] and CDevProc. Should
1737
     * CDevProc to be applied to Metrics[2] or to the metrics
1738
     * from glyph code ? Currently we keep a compatibility
1739
     * to the native GS font renderer without a deep analyzis.
1740
     */
1741
1742
    /* Don't allow caching if we're only returning the metrics */
1743
6.14k
    if (I->ff.metrics_only) {
1744
291
        pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1745
291
    }
1746
1747
6.14k
    if (pgs->in_cachedevice == CACHE_DEVICE_CACHING) {
1748
0
        sbwp = sbw;
1749
0
    }
1750
6.14k
    else {
1751
        /* Very occasionally, if we don't do this, setcachedevice2
1752
         * will decide we are cacheing, when we're not, and this
1753
         * causes problems when we get to show_update().
1754
         */
1755
6.14k
        sbwp = NULL;
1756
1757
6.14k
        if (I->use_outline) {
1758
            /* HACK!!
1759
             * The decision about whether to cache has already been
1760
             * we need to prevent it being made again....
1761
             */
1762
2.16k
            pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1763
2.16k
        }
1764
6.14k
    }
1765
1766
6.14k
    if (bCID) {
1767
702
        code =
1768
702
            I->ff.fapi_set_cache(penum, pbfont, &enc_char_name_string, index + GS_MIN_CID_GLYPH,
1769
702
                                 sbw + 2, &char_bbox, sbwp, &imagenow);
1770
702
    }
1771
5.44k
    else {
1772
5.44k
        code =
1773
5.44k
            I->ff.fapi_set_cache(penum, pbfont, &enc_char_name_string, index,
1774
5.44k
                                 sbw + 2, &char_bbox, sbwp, &imagenow);
1775
5.44k
    }
1776
1777
    /* If we can render the glyph now, do so.
1778
     * we may not be able to in the PS world if there's a CDevProc in the font
1779
     * in which case gs_fapi_finish_render() will be called from the PS
1780
     * "function" zfapi_finish_render() which has been pushed onto the
1781
     * stack.
1782
     */
1783
6.14k
    if (code >= 0 && imagenow == true) {
1784
5.85k
        code = gs_fapi_finish_render(pfont, pgs, penum, I);
1785
5.85k
        I->release_char_data(I);
1786
5.85k
    }
1787
1788
6.14k
    if (code != 0) {
1789
291
        if (code < 0) {
1790
            /* An error */
1791
0
            I->release_char_data(I);
1792
0
        }
1793
291
        else {
1794
            /* Callout to CDevProc, zsetcachedevice2, zfapi_finish_render. */
1795
291
        }
1796
291
    }
1797
1798
6.14k
    return code;
1799
6.14k
}
1800
1801
int
1802
gs_fapi_get_font_info(gs_font *pfont, gs_fapi_font_info item, int index,
1803
                      void *data, int *data_len)
1804
0
{
1805
0
    int code = 0;
1806
0
    gs_font_base *pbfont = (gs_font_base *) pfont;
1807
0
    gs_fapi_server *I = pbfont->FAPI;
1808
1809
0
    code = I->get_font_info(I, &I->ff, item, index, data, data_len);
1810
0
    return (code);
1811
0
}
1812
1813
/* On finding a suitable FAPI instance, fapi_id will be set to point to the string of the instance name.
1814
 * A specific FAPI instance can be requested with the "fapi_request" parameter, but if the requested
1815
 * isn't found, or rejects the font, we're re-search the available instances to find one that can handle
1816
 * the font. If only an exact match is suitable, it is up to the *caller* to enforce that.
1817
 */
1818
int
1819
gs_fapi_passfont(gs_font *pfont, int subfont, char *font_file_path,
1820
                 gs_string *full_font_buf, char *fapi_request, char *xlatmap,
1821
                 char **fapi_id, char **decodingID, gs_fapi_get_server_param_callback get_server_param_cb)
1822
85.3k
{
1823
85.3k
    gs_font_base *pbfont;
1824
85.3k
    int code = 0;
1825
85.3k
    gs_fapi_server *I, **list;
1826
85.3k
    bool free_params = false;
1827
85.3k
    gs_memory_t *mem = pfont->memory;
1828
85.3k
    const char *ldecodingID = NULL;
1829
85.3k
    bool do_restart = false;
1830
1831
85.3k
    list = gs_fapi_get_server_list(mem);
1832
1833
85.3k
    if (!list) /* Should never happen */
1834
0
      return_error(gs_error_unregistered);
1835
1836
85.3k
    (*fapi_id) = NULL;
1837
1838
85.3k
    pbfont = (gs_font_base *) pfont;
1839
1840
85.3k
    I = *list;
1841
1842
85.3k
    if (fapi_request) {
1843
0
        if (gs_debug_c('1'))
1844
0
            dprintf1("Requested FAPI plugin: %s ", fapi_request);
1845
1846
0
        while ((I = *list) != NULL
1847
0
               && strncmp(I->ig.d->subtype, fapi_request,
1848
0
                          strlen(fapi_request)) != 0) {
1849
0
            list++;
1850
0
        }
1851
0
        if (!I) {
1852
0
            if (gs_debug_c('1'))
1853
0
                dprintf("not found. Falling back to normal plugin search\n");
1854
0
            list = (gs_fapi_server **) gs_fapi_get_server_list(mem);
1855
0
            I = *list;
1856
0
        }
1857
0
        else {
1858
0
            if (gs_debug_c('1'))
1859
0
                dprintf("found.\n");
1860
0
            do_restart = true;
1861
0
        }
1862
0
    }
1863
1864
85.6k
    while (I) {
1865
85.4k
        char *server_param = NULL;
1866
85.4k
        int server_param_size = 0;
1867
1868
85.4k
        code = (*get_server_param_cb) (I, (const char *)I->ig.d->subtype,
1869
85.4k
                                &server_param, &server_param_size);
1870
1871
85.4k
        if (code < 0)
1872
0
            return code;
1873
1874
85.4k
        if (server_param == NULL && server_param_size > 0) {
1875
0
            server_param =
1876
0
                (char *)gs_alloc_bytes_immovable(mem->non_gc_memory,
1877
0
                                         server_param_size,
1878
0
                                         "gs_fapi_passfont server params");
1879
0
            if (!server_param) {
1880
0
                return_error(gs_error_VMerror);
1881
0
            }
1882
0
            free_params = true;
1883
0
            (*get_server_param_cb) (I, (const char *)I->ig.d->subtype,
1884
0
                                    &server_param, &server_param_size);
1885
0
        }
1886
1887
85.4k
        if ((code =
1888
85.4k
             gs_fapi_renderer_retcode(mem, I,
1889
85.4k
                                      I->ensure_open(I, server_param,
1890
85.4k
                                                     server_param_size))) < 0) {
1891
0
            gs_free_object(mem->non_gc_memory, server_param,
1892
0
                           "gs_fapi_passfont server params");
1893
0
            return code;
1894
0
        }
1895
1896
85.4k
        if (free_params) {
1897
0
            gs_free_object(mem->non_gc_memory, server_param,
1898
0
                           "gs_fapi_passfont server params");
1899
0
        }
1900
1901
85.4k
        pbfont->FAPI = I;       /* we need the FAPI server during this stage */
1902
85.4k
        code =
1903
85.4k
            gs_fapi_prepare_font(pfont, I, subfont, font_file_path,
1904
85.4k
                                 full_font_buf, xlatmap, &ldecodingID);
1905
85.4k
        if (code >= 0) {
1906
85.2k
            if (decodingID != NULL)
1907
84.2k
                *decodingID = (char *)ldecodingID;
1908
85.2k
            (*fapi_id) = (char *)I->ig.d->subtype;
1909
85.2k
            return 0;
1910
85.2k
        }
1911
1912
        /* renderer failed, continue search */
1913
250
        pbfont->FAPI = NULL;
1914
250
        if (do_restart == true) {
1915
0
            if (gs_debug_c('1'))
1916
0
                dprintf1
1917
0
                    ("Requested FAPI plugin %s failed, searching for alternative plugin\n",
1918
0
                     I->ig.d->subtype);
1919
0
            list = (gs_fapi_server **) gs_fapi_get_server_list(mem);
1920
0
            do_restart = false;
1921
0
        }
1922
250
        else {
1923
250
            I = *list;
1924
250
            list++;
1925
250
        }
1926
250
    }
1927
125
    return (code);
1928
85.3k
}
1929
1930
bool
1931
gs_fapi_available(gs_memory_t *mem, char *server)
1932
104k
{
1933
104k
    bool retval = false;
1934
1935
104k
    if (server) {
1936
10.3k
        gs_fapi_server *serv = NULL;
1937
1938
10.3k
        retval = (gs_fapi_find_server(mem, server, &serv, NULL) >= 0);
1939
10.3k
    }
1940
94.6k
    else {
1941
94.6k
        retval = ((mem->gs_lib_ctx->fapi_servers) != NULL) && (*(mem->gs_lib_ctx->fapi_servers) != NULL);
1942
94.6k
    }
1943
104k
    return (retval);
1944
104k
}
1945
1946
void
1947
gs_fapi_set_servers_client_data(gs_memory_t *mem, const gs_fapi_font *ff_proto, void *ctx_ptr)
1948
117k
{
1949
117k
    gs_fapi_server **servs = gs_fapi_get_server_list(mem);
1950
1951
117k
    if (servs) {
1952
235k
        while (*servs) {
1953
117k
            (*servs)->client_ctx_p = ctx_ptr;
1954
117k
            if (ff_proto)
1955
101k
                (*servs)->ff = *ff_proto;
1956
117k
            servs++;
1957
117k
        }
1958
117k
    }
1959
117k
}
1960
1961
gs_fapi_server **
1962
gs_fapi_get_server_list(gs_memory_t *mem)
1963
229k
{
1964
229k
    return (mem->gs_lib_ctx->fapi_servers);
1965
229k
}
1966
1967
int
1968
gs_fapi_find_server(gs_memory_t *mem, const char *name, gs_fapi_server **server,
1969
                    gs_fapi_get_server_param_callback get_server_param_cb)
1970
25.9k
{
1971
25.9k
    gs_fapi_server **servs = gs_fapi_get_server_list(mem);
1972
25.9k
    char *server_param = NULL;
1973
25.9k
    int server_param_size = 0;
1974
25.9k
    int code = 0;
1975
25.9k
    bool free_params = false;
1976
1977
25.9k
    (*server) = NULL;
1978
1979
36.2k
    while (servs && *servs && strcmp((char *)(*servs)->ig.d->subtype, (char *)name)) {
1980
10.3k
        servs++;
1981
10.3k
    }
1982
1983
25.9k
    if (servs && *servs && get_server_param_cb) {
1984
15.6k
        code = (*get_server_param_cb) ((*servs), (char *) (*servs)->ig.d->subtype,
1985
15.6k
                                &server_param, &server_param_size);
1986
1987
15.6k
        if (code < 0)
1988
0
            return code;
1989
1990
15.6k
        if (server_param == NULL && server_param_size > 0) {
1991
0
            server_param =
1992
0
                (char *)gs_alloc_bytes_immovable(mem->non_gc_memory,
1993
0
                                         server_param_size,
1994
0
                                         "gs_fapi_find_server server params");
1995
0
            if (!server_param) {
1996
0
                return_error(gs_error_VMerror);
1997
0
            }
1998
0
            free_params = true;
1999
0
            (*get_server_param_cb) ((*servs),
2000
0
                                    (const char *)(*servs)->ig.d->subtype,
2001
0
                                    &server_param, &server_param_size);
2002
0
        }
2003
2004
15.6k
        code = gs_fapi_renderer_retcode(mem, (*servs),
2005
15.6k
                                 (*servs)->ensure_open((*servs),
2006
15.6k
                                                       server_param,
2007
15.6k
                                                       server_param_size));
2008
2009
15.6k
        if (free_params) {
2010
0
            gs_free_object(mem->non_gc_memory, server_param,
2011
0
                           "gs_fapi_find_server: server_param");
2012
0
        }
2013
2014
15.6k
        (*server) = (*servs);
2015
15.6k
    }
2016
10.3k
    else {
2017
10.3k
        if (!servs || !(*servs)) {
2018
10.3k
            code = gs_error_invalidaccess;
2019
10.3k
        }
2020
10.3k
    }
2021
2022
2023
25.9k
    return (code);
2024
25.9k
}
2025
2026
int
2027
gs_fapi_init(gs_memory_t *mem)
2028
10.3k
{
2029
10.3k
    int code = 0;
2030
10.3k
    int i, num_servers = 0;
2031
10.3k
    gs_fapi_server **servs = NULL;
2032
10.3k
    const gs_fapi_server_init_func *gs_fapi_server_inits =
2033
10.3k
        gs_get_fapi_server_inits();
2034
2035
20.6k
    while (gs_fapi_server_inits[num_servers]) {
2036
10.3k
        num_servers++;
2037
10.3k
    }
2038
2039
10.3k
    servs =
2040
10.3k
        (gs_fapi_server **) gs_alloc_bytes_immovable(mem->non_gc_memory,
2041
10.3k
                                                     (num_servers +
2042
10.3k
                                                      1) *
2043
10.3k
                                                     sizeof(gs_fapi_server *),
2044
10.3k
                                                     "gs_fapi_init");
2045
10.3k
    if (!servs) {
2046
0
        return_error(gs_error_VMerror);
2047
0
    }
2048
2049
20.6k
    for (i = 0; i < num_servers; i++) {
2050
10.3k
        gs_fapi_server_init_func *f =
2051
10.3k
            (gs_fapi_server_init_func *) & (gs_fapi_server_inits[i]);
2052
2053
10.3k
        code = (*f) (mem, &(servs[i]));
2054
10.3k
        if (code != 0) {
2055
0
            break;
2056
0
        }
2057
        /* No point setting this, as in PS, the interpreter context might move
2058
         * But set it to NULL, just for safety */
2059
10.3k
        servs[i]->client_ctx_p = NULL;
2060
10.3k
    }
2061
2062
20.6k
    for (; i < num_servers + 1; i++) {
2063
10.3k
        servs[i] = NULL;
2064
10.3k
    }
2065
2066
10.3k
    mem->gs_lib_ctx->fapi_servers = servs;
2067
2068
10.3k
    return (code);
2069
10.3k
}
2070
2071
void
2072
gs_fapi_finit(gs_memory_t *mem)
2073
10.3k
{
2074
10.3k
    gs_fapi_server **servs = mem->gs_lib_ctx->fapi_servers;
2075
2076
20.6k
    while (servs && *servs) {
2077
10.3k
        ((*servs)->ig.d->finit) (servs);
2078
10.3k
        servs++;
2079
10.3k
    }
2080
10.3k
    gs_free_object(mem->non_gc_memory, mem->gs_lib_ctx->fapi_servers,
2081
10.3k
                   "gs_fapi_finit: mem->gs_lib_ctx->fapi_servers");
2082
10.3k
    mem->gs_lib_ctx->fapi_servers = NULL;
2083
10.3k
}