Coverage Report

Created: 2025-06-10 06:59

/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
314k
#define FAPI_ROUND(v) (v >= 0 ? v + 0.5 : v - 0.5)
43
314k
#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
1.12M
{
52
1.12M
    if (rc == 0)
53
1.11M
        return 0;
54
5.07k
    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
5.07k
    return rc < 0 ? rc : gs_error_invalidfont;
60
1.12M
}
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
1.10M
{
75
1.10M
    return (n > 0 ? (x << n) : (x >> -n));
76
1.10M
}
77
78
static inline int
79
export_shift(int x, int n)
80
14.2k
{
81
14.2k
    return (n > 0 ? (x >> n) : (x << -n));
82
14.2k
}
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
24.7k
{
93
24.7k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
94
95
24.7k
    if (olh->need_close == true) {
96
23.9k
        olh->need_close = false;
97
23.9k
        I->gs_error = gx_path_close_subpath_notes(olh->path, 0);
98
23.9k
    }
99
24.7k
    return (I->gs_error);
100
24.7k
}
101
102
static int
103
add_move(gs_fapi_path *I, int64_t x, int64_t y)
104
28.5k
{
105
28.5k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
106
107
28.5k
    x = import_shift(x, I->shift);
108
28.5k
    y = -import_shift(y, I->shift);
109
28.5k
    if (olh->fserver->transform_outline) {
110
1.63k
        gs_point pt;
111
1.63k
        I->gs_error = gs_distance_transform((double)fixed2float((float)x), (double)fixed2float((float)y), &olh->fserver->outline_mat, &pt);
112
1.63k
        if (I->gs_error < 0)
113
0
            return I->gs_error;
114
1.63k
        x = float2fixed(pt.x);
115
1.63k
        y = float2fixed(pt.y);
116
1.63k
    }
117
28.5k
    x += olh->x0;
118
28.5k
    y += olh->y0;
119
120
28.5k
    if (x > (int64_t) max_coord_fixed || x < (int64_t) min_coord_fixed
121
28.5k
     || y > (int64_t) max_coord_fixed || y < (int64_t) min_coord_fixed) {
122
1.45k
         I->gs_error = gs_error_undefinedresult;
123
1.45k
    }
124
27.0k
    else {
125
126
27.0k
        if (olh->need_close && olh->close_path)
127
7.29k
            if ((I->gs_error = add_closepath(I)) < 0)
128
0
                return (I->gs_error);
129
27.0k
        olh->need_close = false;
130
131
/*        dprintf2("%f %f moveto\n", fixed2float(x), fixed2float(y)); */
132
27.0k
        I->gs_error = gx_path_add_point(olh->path, (fixed) x, (fixed) y);
133
27.0k
    }
134
28.5k
    return (I->gs_error);
135
28.5k
}
136
137
static int
138
add_line(gs_fapi_path *I, int64_t x, int64_t y)
139
109k
{
140
109k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
141
142
109k
    x = import_shift(x, I->shift);
143
109k
    y = -import_shift(y, I->shift);
144
109k
    if (olh->fserver->transform_outline) {
145
1.07k
        gs_point pt;
146
1.07k
        I->gs_error = gs_distance_transform((double)fixed2float((float)x), (double)fixed2float((float)y), &olh->fserver->outline_mat, &pt);
147
1.07k
        if (I->gs_error < 0)
148
0
            return I->gs_error;
149
1.07k
        x = float2fixed(pt.x);
150
1.07k
        y = float2fixed(pt.y);
151
1.07k
    }
152
109k
    x += olh->x0;
153
109k
    y += olh->y0;
154
155
109k
    if (x > (int64_t) max_coord_fixed || x < (int64_t) min_coord_fixed
156
109k
     || y > (int64_t) max_coord_fixed || y < (int64_t) min_coord_fixed) {
157
1.91k
         I->gs_error = gs_error_undefinedresult;
158
1.91k
    }
159
107k
    else {
160
107k
        olh->need_close = true;
161
162
/*        dprintf2("%f %f lineto\n", fixed2float(x), fixed2float(y)); */
163
107k
        I->gs_error = gx_path_add_line_notes(olh->path, (fixed) x, (fixed) y, 0);
164
107k
    }
165
109k
    return (I->gs_error);
166
109k
}
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
137k
{
172
137k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
173
174
137k
    x0 = import_shift(x0, I->shift);
175
137k
    y0 = -import_shift(y0, I->shift);
176
137k
    x1 = import_shift(x1, I->shift);
177
137k
    y1 = -import_shift(y1, I->shift);
178
137k
    x2 = import_shift(x2, I->shift);
179
137k
    y2 = -import_shift(y2, I->shift);
180
181
137k
    if (olh->fserver->transform_outline) {
182
385
        gs_point pt;
183
385
        I->gs_error = gs_distance_transform((double)fixed2float((float)x0), (double)fixed2float((float)y0), &olh->fserver->outline_mat, &pt);
184
385
        if (I->gs_error < 0)
185
0
            return I->gs_error;
186
385
        x0 = float2fixed(pt.x);
187
385
        y0 = float2fixed(pt.y);
188
385
        I->gs_error = gs_distance_transform((double)fixed2float((float)x1), (double)fixed2float((float)y1), &olh->fserver->outline_mat, &pt);
189
385
        if (I->gs_error < 0)
190
0
            return I->gs_error;
191
385
        x1 = float2fixed(pt.x);
192
385
        y1 = float2fixed(pt.y);
193
385
        I->gs_error = gs_distance_transform((double)fixed2float((float)x2), (double)fixed2float((float)y2), &olh->fserver->outline_mat, &pt);
194
385
        if (I->gs_error < 0)
195
0
            return I->gs_error;
196
385
        x2 = float2fixed(pt.x);
197
385
        y2 = float2fixed(pt.y);
198
385
    }
199
137k
    x0 += olh->x0;
200
137k
    y0 += olh->y0;
201
137k
    x1 += olh->x0;
202
137k
    y1 += olh->y0;
203
137k
    x2 += olh->x0;
204
137k
    y2 += olh->y0;
205
206
137k
    if (x0 > (int64_t) max_coord_fixed || x0 < (int64_t) min_coord_fixed
207
137k
     || y0 > (int64_t) max_coord_fixed || y0 < (int64_t) min_coord_fixed
208
137k
     || x1 > (int64_t) max_coord_fixed || x1 < (int64_t) min_coord_fixed
209
137k
     || y1 > (int64_t) max_coord_fixed || y1 < (int64_t) min_coord_fixed
210
137k
     || x2 > (int64_t) max_coord_fixed || x2 < (int64_t) min_coord_fixed
211
137k
     || y2 > (int64_t) max_coord_fixed || y2 < (int64_t) min_coord_fixed)
212
1.17k
    {
213
1.17k
        I->gs_error = gs_error_undefinedresult;
214
1.17k
    }
215
136k
    else {
216
136k
        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
136k
        I->gs_error = gx_path_add_curve_notes(olh->path, (fixed) x0, (fixed) y0, (fixed) x1, (fixed) y1, (fixed) x2, (fixed) y2, 0);
220
136k
    }
221
137k
    return (I->gs_error);
222
137k
}
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
476k
{
230
476k
    if (!ff->is_type1 && ff->is_cid) {
231
35.2k
        gs_font_cid2 *pfcid = (gs_font_cid2 *) ff->client_font_data;
232
233
35.2k
        return (pfcid->cidata.MetricsCount);
234
35.2k
    }
235
440k
    return 0;
236
476k
}
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
421k
{
249
421k
    if (!gs_text_is_width_only(penum))
250
385k
        return false;
251
36.3k
    switch (penum->orig_font->FontType) {
252
34.6k
        case ft_encrypted:
253
34.6k
        case ft_encrypted2:
254
34.6k
        case ft_CID_encrypted:
255
34.6k
        case ft_CID_TrueType:
256
34.6k
        case ft_CID_bitmap:
257
35.5k
        case ft_TrueType:
258
35.5k
            return true;
259
793
        default:
260
793
            return false;
261
36.3k
    }
262
36.3k
}
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
419k
{
274
419k
    gx_device *dev = gs_currentdevice_inline(pgs);
275
276
419k
    return ((!gs_color_writes_pure(pgs)) && dev_proc(dev, dev_spec_op)(dev, gxdso_supports_pattern_transparency, NULL, 0));
277
419k
}
278
279
static inline bool
280
recreate_multiple_master(gs_font_base *pbfont)
281
421k
{
282
421k
    bool r = false;
283
421k
    gs_fapi_server *I = pbfont->FAPI;
284
421k
    bool changed = false;
285
286
421k
    if (I && I->face.font_id != gs_no_id &&
287
421k
        (pbfont->FontType == ft_encrypted
288
390k
        || pbfont->FontType == ft_encrypted2)) {
289
340k
        gs_font_type1 *pfont1 = (gs_font_type1 *) pbfont;
290
340k
        if (pfont1->data.WeightVector.count != 0
291
340k
            && I->face.WeightVector.count != pfont1->data.WeightVector.count) {
292
0
            changed = true;
293
0
        }
294
340k
        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
340k
        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
340k
    }
306
421k
    return r;
307
421k
}
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
421k
{
314
421k
    gs_gstate *pgs = (gs_gstate *) penum_s->pgs;
315
316
421k
    log2_scale->x = 0;
317
421k
    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
421k
    gx_compute_text_oversampling(penum_s, (gs_font *) pbfont, abits,
326
421k
                                 log2_scale);
327
328
421k
    return (pgs->in_charpath || pbfont->PaintType != 0 ||
329
421k
            (pgs->in_cachedevice != CACHE_DEVICE_CACHING
330
419k
             && using_transparency_pattern((gs_gstate *) penum_s->pgs))
331
421k
            || (pgs->in_cachedevice != CACHE_DEVICE_CACHING
332
419k
                && (log2_scale->x > 0 || log2_scale->y > 0))
333
421k
            || (pgs->in_cachedevice != CACHE_DEVICE_CACHING && abits > 1));
334
421k
}
335
336
static inline void
337
gs_fapi_release_typeface(gs_fapi_server *I, void **server_font_data)
338
53.0k
{
339
53.0k
    I->release_typeface(I, *server_font_data);
340
53.0k
    I->face.font_id = gs_no_id;
341
53.0k
    if (I->ff.server_font_data == *server_font_data)
342
13.2k
        I->ff.server_font_data = 0;
343
53.0k
    *server_font_data = 0;
344
53.0k
}
345
346
static int
347
notify_remove_font(void *proc_data, void *event_data)
348
54.2k
{                               /* gs_font_finalize passes event_data == NULL, so check it here. */
349
54.2k
    if (event_data == NULL) {
350
54.2k
        gs_font_base *pbfont = proc_data;
351
54.2k
        gs_fapi_server *I = pbfont->FAPI;
352
353
54.2k
        if (pbfont->FAPI_font_data != 0) {
354
53.0k
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
355
53.0k
        }
356
54.2k
    }
357
54.2k
    return 0;
358
54.2k
}
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
54.1k
{                               /* 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
54.1k
    gs_memory_t *mem = pfont->memory;
386
54.1k
    gs_font_base *pbfont = (gs_font_base *)pfont;
387
54.1k
    int code, bbox_set = 0;
388
54.1k
    int BBox[4], scale;
389
54.1k
    int units[2];
390
54.1k
    double size;
391
54.1k
    gs_fapi_font_scale font_scale =
392
54.1k
        { {1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true };
393
394
54.1k
    scale = 1 << I->frac_shift;
395
54.1k
    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
54.1k
    if (size < 1000)
400
53.7k
        size = 1000;
401
402
54.1k
    font_scale.matrix[0] = font_scale.matrix[3] = (int)(size * scale + 0.5);
403
404
54.1k
    font_scale.HWResolution[0] = (fracint) (72 * scale);
405
54.1k
    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
54.1k
    I->ff.subfont = subfont;
411
54.1k
    I->ff.font_file_path = font_file_path;
412
54.1k
    I->ff.is_type1 = FAPI_ISTYPE1GLYPHDATA(pbfont);
413
54.1k
    I->ff.is_vertical = (pbfont->WMode != 0);
414
54.1k
    I->ff.memory = mem;
415
54.1k
    I->ff.client_ctx_p = I->client_ctx_p;
416
54.1k
    I->ff.client_font_data = pbfont;
417
54.1k
    I->ff.client_font_data2 = pbfont;
418
54.1k
    I->ff.server_font_data = pbfont->FAPI_font_data;    /* Possibly pass it from zFAPIpassfont. */
419
54.1k
    if (full_font_buf) {
420
40.0k
        I->ff.full_font_buf = (char *)full_font_buf->data;
421
40.0k
        I->ff.full_font_buf_len = full_font_buf->size;
422
40.0k
    }
423
14.1k
    else {
424
14.1k
        I->ff.full_font_buf = NULL;
425
14.1k
        I->ff.full_font_buf_len = 0;
426
14.1k
    }
427
54.1k
    I->ff.is_cid = FAPI_ISCIDFONT(pbfont);
428
54.1k
    I->ff.is_outline_font = pbfont->PaintType != 0;
429
430
54.1k
    if (!I->ff.is_mtx_skipped)
431
54.1k
        I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
432
433
54.1k
    if ((code = gs_fapi_renderer_retcode(mem, I, I->get_scaled_font(I, &I->ff,
434
54.1k
                                                                    (const
435
54.1k
                                                                     gs_fapi_font_scale
436
54.1k
                                                                     *)
437
54.1k
                                                                    &font_scale, xlatmap, gs_fapi_toplevel_begin)))
438
54.1k
        < 0)
439
76
        return code;
440
54.0k
    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
54.0k
    if (I->ff.server_font_data != 0
448
54.0k
        && (font_file_path != NULL || full_font_buf != NULL)) {
449
39.9k
        if ((code =
450
39.9k
             gs_fapi_renderer_retcode(mem, I,
451
39.9k
                                      I->get_font_bbox(I, &I->ff,
452
39.9k
                                                       BBox, units))) < 0) {
453
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
454
0
            return code;
455
0
        }
456
        /* Refine FontBBox : */
457
39.9k
        pbfont->FontBBox.p.x = ((double)BBox[0] / units[0]);
458
39.9k
        pbfont->FontBBox.p.y = ((double)BBox[1] / units[1]);
459
39.9k
        pbfont->FontBBox.q.x = ((double)BBox[2] / units[0]);
460
39.9k
        pbfont->FontBBox.q.y = ((double)BBox[3] / units[1]);
461
462
39.9k
        bbox_set = 1;
463
39.9k
    }
464
465
54.0k
    if (xlatmap != NULL && pbfont->FAPI_font_data != NULL) {
466
770
        if ((code =
467
770
             gs_fapi_renderer_retcode(mem, I,
468
770
                                      I->get_decodingID(I, &I->ff,
469
770
                                                        decodingID))) < 0) {
470
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
471
0
            return code;
472
0
        }
473
770
    }
474
475
    /* Prepare descendant fonts : */
476
54.0k
    if (font_file_path == NULL && I->ff.is_type1 && I->ff.is_cid) {     /* Renderers should expect same condition. */
477
86
        gs_font_cid0 *pfcid = (gs_font_cid0 *) pbfont;
478
86
        gs_font_type1 **FDArray = pfcid->cidata.FDArray;
479
86
        int i, n = pfcid->cidata.FDArray_size;
480
481
86
        I->ff.is_type1 = true;
482
86
        I->ff.is_vertical = false;      /* A subfont may be shared with another fonts. */
483
86
        I->ff.memory = mem;
484
86
        I->ff.client_ctx_p = I->client_ctx_p;
485
284
        for (i = 0; i < n; i++) {
486
198
            gs_font_type1 *pbfont1 = FDArray[i];
487
198
            int BBox_temp[4];
488
198
            int units_temp[2];
489
490
198
            pbfont1->FontBBox = pbfont->FontBBox;       /* Inherit FontBBox from the type 9 font. */
491
492
198
            I->ff.client_font_data = pbfont1;
493
198
            pbfont1->FAPI = pbfont->FAPI;
494
198
            I->ff.client_font_data2 = pbfont1;
495
198
            I->ff.server_font_data = pbfont1->FAPI_font_data;
496
198
            I->ff.is_cid = true;
497
198
            I->ff.is_outline_font = pbfont1->PaintType != 0;
498
198
            if (!I->ff.is_mtx_skipped)
499
198
                I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
500
198
            I->ff.subfont = 0;
501
198
            if ((code =
502
198
                 gs_fapi_renderer_retcode(mem, I,
503
198
                                          I->get_scaled_font(I, &I->ff,
504
198
                                                             (const
505
198
                                                              gs_fapi_font_scale
506
198
                                                              *)&font_scale,
507
198
                                                             NULL, i))) < 0) {
508
0
                break;
509
0
            }
510
511
198
            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
198
            if ((code =
514
198
                 gs_fapi_renderer_retcode(mem, I,
515
198
                                          I->get_font_bbox(I, &I->ff,
516
198
                                                           BBox_temp, units_temp))) < 0) {
517
0
                break;
518
0
            }
519
198
            code = gs_notify_register(&pbfont1->notify_list, notify_remove_font, pbfont1);
520
198
            if (code < 0) {
521
0
                emprintf(mem,
522
0
                         "Ignoring gs_notify_register() failure for FAPI font.....");
523
0
            }
524
198
        }
525
86
        if (i == n) {
526
86
            code =
527
86
                gs_fapi_renderer_retcode(mem, I,
528
86
                                         I->get_scaled_font(I, &I->ff,
529
86
                                                            (const
530
86
                                                             gs_fapi_font_scale
531
86
                                                             *)&font_scale,
532
86
                                                            NULL,
533
86
                                                            gs_fapi_toplevel_complete));
534
86
            if (code >= 0)
535
86
                return bbox_set;        /* Full success. */
536
86
        }
537
        /* Fail, release server's font data : */
538
0
        for (i = 0; i < n; i++) {
539
0
            gs_font_type1 *pbfont1 = FDArray[i];
540
541
0
            if (pbfont1->FAPI_font_data != NULL)
542
0
                gs_fapi_release_typeface(I, &pbfont1->FAPI_font_data);
543
0
        }
544
545
0
        if (pbfont->FAPI_font_data != NULL) {
546
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
547
0
        }
548
0
        return_error(gs_error_invalidfont);
549
86
    }
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
54.0k
    code = gs_fapi_renderer_retcode(mem, I, I->get_scaled_font(I, &I->ff,
555
54.0k
                                                               (const
556
54.0k
                                                                gs_fapi_font_scale
557
54.0k
                                                                *)&font_scale,
558
54.0k
                                                               xlatmap,
559
54.0k
                                                               gs_fapi_toplevel_complete));
560
54.0k
    if (code < 0) {
561
0
        gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
562
0
        return code;
563
0
    }
564
54.0k
    code =
565
54.0k
        gs_notify_register(&pbfont->notify_list, notify_remove_font, pbfont);
566
54.0k
    if (code < 0) {
567
0
        gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
568
0
        return code;
569
0
    }
570
571
54.0k
    return bbox_set;
572
54.0k
}
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
22.0k
{
579
22.0k
    gs_fapi_path path_interface = path_interface_stub;
580
22.0k
    gs_fapi_outline_handler olh;
581
22.0k
    int code = 0;
582
22.0k
    gs_gstate *pgs = penum_s->pgs;
583
22.0k
    struct gx_path_s path1;
584
585
22.0k
    (void)gx_path_init_local(&path1, mem);
586
587
22.0k
    olh.fserver = I;
588
22.0k
    olh.path = &path1;
589
22.0k
    olh.x0 = pgs->ctm.tx_fixed - float2fixed(penum_s->fapi_glyph_shift.x);
590
22.0k
    olh.y0 = pgs->ctm.ty_fixed - float2fixed(penum_s->fapi_glyph_shift.y);
591
22.0k
    olh.close_path = close_path;
592
22.0k
    olh.need_close = false;
593
22.0k
    path_interface.olh = &olh;
594
22.0k
    path_interface.shift = import_shift_v;
595
22.0k
    if ((code =
596
22.0k
         gs_fapi_renderer_retcode(mem, I,
597
22.0k
                                  I->get_char_outline(I,
598
22.0k
                                                      &path_interface))) < 0
599
22.0k
        || path_interface.gs_error != 0) {
600
4.54k
        if (path_interface.gs_error != 0) {
601
4.54k
            code = path_interface.gs_error;
602
4.54k
            goto done;
603
4.54k
        }
604
0
        else {
605
0
            goto done;
606
0
        }
607
4.54k
    }
608
17.4k
    if (olh.need_close && olh.close_path)
609
0
        if ((code = add_closepath(&path_interface)) < 0)
610
0
            goto done;
611
17.4k
    code = gx_path_copy(&path1, path);
612
22.0k
done:
613
22.0k
    code = code >= 0 || code == gs_error_undefinedresult ? 0 : code;
614
22.0k
    gx_path_free(&path1, "outline_char");
615
22.0k
    return code;
616
17.4k
}
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
421k
{                               /* optimize : move this stuff to FAPI_refine_font */
623
421k
    gs_matrix mat;
624
421k
    gs_matrix *m = &mat;
625
421k
    int rounding_x, rounding_y; /* Striking out the 'float' representation error in FontMatrix. */
626
421k
    double sx, sy;
627
421k
    gs_fapi_server *I = pbfont->FAPI;
628
629
421k
#if 1
630
421k
    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
421k
    if (m->xx == 0 && m->xy == 0 && m->yx == 0 && m->yy == 0)
638
0
        m = &pbfont->base->FontMatrix;
639
421k
    sx = hypot(m->xx, m->xy) * metrics->em_x / FontMatrix_div;
640
421k
    sy = hypot(m->yx, m->yy) * metrics->em_y / FontMatrix_div;
641
421k
    rounding_x = (int)(0x00800000 / sx);
642
421k
    rounding_y = (int)(0x00800000 / sy);
643
421k
    *em_scale_x = (int)(sx * rounding_x + 0.5) / (double)rounding_x;
644
421k
    *em_scale_y = (int)(sy * rounding_y + 0.5) / (double)rounding_y;
645
421k
}
646
647
static int
648
fapi_copy_mono(gx_device *dev1, gs_fapi_raster *rast, int dx, int dy)
649
352k
{
650
352k
    int line_step = bitmap_raster(rast->width), code;
651
652
352k
    if (rast->line_step >= line_step) {
653
2.03k
        return dev_proc(dev1, copy_mono) (dev1, rast->p, 0, rast->line_step,
654
2.03k
                                          0, dx, dy, rast->width,
655
2.03k
                                          rast->height, 0, 1);
656
2.03k
    }
657
350k
    else {                      /* bitmap data needs to be aligned, make the aligned copy : */
658
350k
        byte *p = gs_alloc_byte_array(dev1->memory, rast->height, line_step,
659
350k
                                      "fapi_copy_mono");
660
350k
        byte *q = p, *r = rast->p, *pe;
661
662
350k
        if (p == NULL)
663
0
            return_error(gs_error_VMerror);
664
350k
        pe = p + rast->height * line_step;
665
6.33M
        for (; q < pe; q += line_step, r += rast->line_step) {
666
5.98M
            memcpy(q, r, rast->line_step);
667
5.98M
            memset(q + rast->line_step, 0, line_step - rast->line_step);
668
5.98M
        }
669
350k
        code =
670
350k
            dev_proc(dev1, copy_mono) (dev1, p, 0, line_step, 0, dx, dy,
671
350k
                                       rast->width, rast->height, 0, 1);
672
350k
        gs_free_object(dev1->memory, p, "fapi_copy_mono");
673
350k
        return code;
674
350k
    }
675
352k
}
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
10.9k
{
827
10.9k
    gx_device *dev = penum->dev;
828
10.9k
    gs_gstate *penum_pgs = (gs_gstate *) penum->pgs;
829
10.9k
    int code;
830
10.9k
    const gx_clip_path *pcpath = pgs->clip_path;
831
10.9k
    const gx_drawing_color *pdcolor = gs_currentdevicecolor_inline(penum->pgs);
832
10.9k
    int rast_orig_x = rast->orig_x;
833
10.9k
    int rast_orig_y = -rast->orig_y;
834
10.9k
    gs_font_base *pbfont = (gs_font_base *)pfont;
835
10.9k
    gs_fapi_server *I = pbfont->FAPI;
836
837
10.9k
    extern_st(st_gs_show_enum);
838
839
10.9k
    byte *r = rast->p;
840
10.9k
    byte *src, *dst;
841
10.9k
    int h, padbytes, cpbytes, dstr = bitmap_raster(rast->width);
842
10.9k
    int sstr = rast->line_step;
843
844
10.9k
    double dx = penum_pgs->ctm.tx + (double)rast_orig_x / (1 << frac_pixel_shift) + 0.5;
845
10.9k
    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
10.9k
    if (gs_color_writes_pure(penum_pgs) && I->ff.embolden == 0.0) {
851
10.6k
        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
8.83k
            r = gs_alloc_bytes(penum->memory, (size_t)dstr * rast->height,
865
8.83k
                               "fapi_finish_render_aux");
866
8.83k
            if (!r) {
867
0
                return_error(gs_error_VMerror);
868
0
            }
869
870
8.83k
            cpbytes = sstr < dstr ? sstr : dstr;
871
8.83k
            padbytes = dstr - cpbytes;
872
8.83k
            h = rast->height;
873
8.83k
            src = rast->p;
874
8.83k
            dst = r;
875
8.83k
            if (padbytes > 0) {
876
514k
                while (h-- > 0) {
877
505k
                    memcpy(dst, src, cpbytes);
878
505k
                    memset(dst + cpbytes, 0, padbytes);
879
505k
                    src += sstr;
880
505k
                    dst += dstr;
881
505k
                }
882
8.83k
            }
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
8.83k
        }
891
892
10.6k
        if (gs_object_type(penum->memory, penum) == &st_gs_show_enum) {
893
10.6k
            dx += penum->fapi_glyph_shift.x;
894
10.6k
            dy += penum->fapi_glyph_shift.y;
895
10.6k
        }
896
        /* Processing an image object operation, but this may be for a text object */
897
10.6k
        ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
898
10.6k
        code = gx_set_dev_color(pgs);
899
10.6k
        if (code != 0)
900
0
            return code;
901
10.6k
        code = gs_gstate_color_load(pgs);
902
10.6k
        if (code < 0)
903
0
            return code;
904
905
10.6k
        code = gx_image_fill_masked(dev, r, 0, dstr, gx_no_bitmap_id,
906
10.6k
                                    (int)dx, (int)dy,
907
10.6k
                                    rast->width, rast->height,
908
10.6k
                                    pdcolor, 1, rop3_default, pcpath);
909
10.6k
        if (rast->p != r) {
910
8.83k
            gs_free_object(penum->memory, r, "fapi_finish_render_aux");
911
8.83k
        }
912
10.6k
    }
913
331
    else {
914
331
        gs_memory_t *mem = penum->memory->non_gc_memory;
915
331
        gs_image_enum *pie;
916
331
        gs_image_t image;
917
331
        int iy, nbytes;
918
331
        uint used;
919
331
        int code1;
920
331
        int w, h;
921
331
        int x = (int)dx;
922
331
        int y = (int)dy;
923
331
        uint bold = 0;
924
331
        byte *bold_lines = NULL;
925
331
        byte *line = NULL;
926
331
        int ascent = 0;
927
928
331
        pie = gs_image_enum_alloc(mem, "image_char(image_enum)");
929
331
        if (!pie) {
930
0
            return_error(gs_error_VMerror);
931
0
        }
932
933
331
        w = rast->width;
934
331
        h = rast->height;
935
331
        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
331
        gs_image_t_init_mask(&image, true);
954
331
        gs_make_translation((double) - x, (double) (- y + ascent), &image.ImageMatrix);
955
331
        gs_matrix_multiply(&ctm_only(penum_pgs), &image.ImageMatrix, &image.ImageMatrix);
956
331
        image.Width = w + bold;
957
331
        image.Height = h + bold;
958
331
        image.adjust = false;
959
331
        code = gs_image_init(pie, &image, false, true, penum_pgs);
960
331
        nbytes = (rast->width + 7) >> 3;
961
962
331
        switch (code) {
963
0
            case 1:            /* empty image */
964
0
                code = 0;
965
0
            default:
966
0
                break;
967
331
            case 0:
968
331
                if (bold == 0) {
969
84.8k
                    for (iy = 0; iy < h && code >= 0; iy++, r += sstr) {
970
84.4k
                        code = gs_image_next(pie, r, nbytes, &used);
971
84.4k
                    }
972
331
                }
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
331
#undef merged_line
1029
331
        }
1030
1031
331
        if (bold_lines)
1032
0
            gs_free_object(pgs->memory, bold_lines, "fapi_image_uncached_glyph(bold_lines)");
1033
1034
331
        if (line)
1035
0
            gs_free_object(pgs->memory, line, "fapi_image_uncached_glyph(line)");
1036
1037
331
        code1 = gs_image_cleanup_and_free_enum(pie, penum_pgs);
1038
331
        if (code >= 0 && code1 < 0)
1039
0
            code = code1;
1040
331
    }
1041
10.9k
    return (code);
1042
10.9k
}
1043
1044
int
1045
gs_fapi_finish_render(gs_font *pfont, gs_gstate *pgs, gs_text_enum_t *penum, gs_fapi_server *I)
1046
421k
{
1047
421k
    gs_show_enum *penum_s = (gs_show_enum *) penum;
1048
421k
    gs_gstate *penum_pgs;
1049
421k
    gx_device *dev1;
1050
421k
    const int import_shift_v = _fixed_shift - 32;       /* we always 32.32 values for the outline interface now */
1051
421k
    gs_fapi_raster rast;
1052
421k
    int code;
1053
421k
    gs_memory_t *mem = pfont->memory;
1054
421k
    gs_font_base *pbfont = (gs_font_base *)pfont;
1055
1056
421k
    if (penum == NULL)
1057
0
        return_error(gs_error_undefined);
1058
1059
421k
    penum_pgs = penum_s->pgs;
1060
1061
421k
    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
421k
    if (pgs->in_charpath && !SHOW_IS(penum, TEXT_DO_NONE)) {
1068
2.25k
        gs_point pt;
1069
1070
2.25k
        if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1071
0
            return code;
1072
1073
2.25k
        if ((code =
1074
2.25k
             outline_char(mem, I, import_shift_v, penum_s, penum_pgs->path,
1075
2.25k
                          !pbfont->PaintType)) < 0) {
1076
0
            return code;
1077
0
        }
1078
1079
2.25k
        if ((code =
1080
2.25k
             gx_path_add_char_path(penum_pgs->show_gstate->path,
1081
2.25k
                                   penum_pgs->path,
1082
2.25k
                                   penum_pgs->in_charpath)) < 0) {
1083
0
            return code;
1084
0
        }
1085
1086
2.25k
    }
1087
418k
    else {
1088
418k
        int code;
1089
418k
        memset(&rast, 0x00, sizeof(rast));
1090
1091
418k
        if ((code = I->get_char_raster(I, &rast)) < 0 && code != gs_error_unregistered)
1092
0
            return code;
1093
1094
418k
        if (!SHOW_IS(penum, TEXT_DO_NONE) && I->use_outline) {
1095
            /* The server provides an outline instead the raster. */
1096
19.7k
            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
19.7k
            if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1105
21
                return code;
1106
1107
19.7k
            if ((code =
1108
19.7k
                 outline_char(mem, I, import_shift_v, penum_s,
1109
19.7k
                              penum_pgs->path, !pbfont->PaintType)) < 0)
1110
0
                return code;
1111
19.7k
            if ((code =
1112
19.7k
                 gs_gstate_setflat((gs_gstate *) penum_pgs,
1113
19.7k
                                   gs_char_flatness(penum_pgs->show_gstate, 1.0))) < 0)
1114
0
                return code;
1115
19.7k
            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
19.7k
            else {
1125
19.7k
                gs_in_cache_device_t in_cachedevice =
1126
19.7k
                    penum_pgs->in_cachedevice;
1127
1128
19.7k
                penum_pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1129
1130
19.7k
                penum_pgs->fill_adjust.x = penum_pgs->fill_adjust.y = 0;
1131
1132
19.7k
                code = gs_fill(penum_pgs);
1133
1134
19.7k
                penum_pgs->in_cachedevice = in_cachedevice;
1135
1136
19.7k
                if (code < 0)
1137
0
                    return code;
1138
19.7k
            }
1139
19.7k
            if ((code = gs_moveto(penum_pgs, pt.x, pt.y)) < 0)
1140
0
                return code;
1141
19.7k
        }
1142
399k
        else {
1143
399k
            int rast_orig_x = rast.orig_x;
1144
399k
            int rast_orig_y = -rast.orig_y;
1145
399k
            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
399k
            if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1154
5
                return code;
1155
1156
399k
            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
352k
                if (rast.width != 0) {
1164
352k
                    int shift_rd = _fixed_shift - frac_pixel_shift;
1165
352k
                    int rounding = 1 << (frac_pixel_shift - 1);
1166
352k
                    int dx =
1167
352k
                        arith_rshift_slow((penum_pgs->
1168
352k
                                           ctm.tx_fixed >> shift_rd) +
1169
352k
                                          rast_orig_x + rounding,
1170
352k
                                          frac_pixel_shift);
1171
352k
                    int dy =
1172
352k
                        arith_rshift_slow((penum_pgs->
1173
352k
                                           ctm.ty_fixed >> shift_rd) +
1174
352k
                                          rast_orig_y + rounding,
1175
352k
                                          frac_pixel_shift);
1176
1177
352k
                    if (dx + rast.left_indent < 0
1178
352k
                        || dx + rast.left_indent + rast.black_width >
1179
352k
                        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
27
                        if (dx + rast.left_indent < 0)
1190
27
                            dx -= dx + rast.left_indent;
1191
27
                    }
1192
352k
                    if (dy + rast.top_indent < 0
1193
352k
                        || dy + rast.top_indent + rast.black_height >
1194
352k
                        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
1
                        if (dy + rast.top_indent < 0)
1205
1
                            dy -= dy + rast.top_indent;
1206
1
                    }
1207
352k
                    if ((code = fapi_copy_mono(dev1, &rast, dx, dy)) < 0)
1208
0
                        return code;
1209
1210
352k
                    if (penum_s->cc != NULL) {
1211
352k
                        penum_s->cc->offset.x +=
1212
352k
                            float2fixed(penum_s->fapi_glyph_shift.x);
1213
352k
                        penum_s->cc->offset.y +=
1214
352k
                            float2fixed(penum_s->fapi_glyph_shift.y);
1215
352k
                    }
1216
352k
                }
1217
352k
            }
1218
46.4k
            else if (!SHOW_IS(penum, TEXT_DO_NONE)) {   /* Not using GS cache */
1219
10.9k
                if ((code =
1220
10.9k
                     fapi_image_uncached_glyph(pfont, pgs, penum_s, &rast,
1221
10.9k
                                               import_shift_v)) < 0)
1222
0
                    return code;
1223
10.9k
            }
1224
399k
        }
1225
418k
    }
1226
1227
421k
    return 0;
1228
421k
}
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
839k
#define MTX_EQ(mtx1,mtx2) (mtx1->xx == mtx2->xx && mtx1->xy == mtx2->xy && \
1235
399k
                           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
421k
{                               /* Stack : <font> <code|name> --> - */
1242
421k
    gs_show_enum *penum_s = (gs_show_enum *) penum;
1243
421k
    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
421k
    gs_fapi_char_ref cr =
1251
421k
        { 0, {0}, 0, false, NULL, 0, 0, 0, 0, 0, gs_fapi_metrics_notdef };
1252
421k
    gs_font_base *pbfont = (gs_font_base *)pfont;
1253
421k
    const gs_matrix *ctm = &ctm_only(pgs);
1254
421k
    int scale;
1255
421k
    gs_fapi_metrics metrics;
1256
421k
    gs_fapi_server *I = pbfont->FAPI;
1257
1258
421k
    gs_string enc_char_name_string;
1259
421k
    bool bCID = (FAPI_ISCIDFONT(pbfont) || charstring != NULL);
1260
421k
    bool bIsType1GlyphData = FAPI_ISTYPE1GLYPHDATA(pbfont);
1261
421k
    gs_log2_scale_point log2_scale = { 0, 0 };
1262
421k
    int alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
1263
421k
    double FontMatrix_div = 1;
1264
421k
    bool bVertical = (gs_rootfont(pgs)->WMode != 0), bVertical0 = bVertical;
1265
421k
    double *sbwp, sbw[4] = { 0, 0, 0, 0 };
1266
421k
    double em_scale_x, em_scale_y;
1267
421k
    gs_rect char_bbox;
1268
421k
    int code;
1269
421k
    bool imagenow = false;
1270
421k
    bool align_to_pixels = gs_currentaligntopixels(pbfont->dir);
1271
421k
    gs_memory_t *mem = pfont->memory;
1272
421k
    enum
1273
421k
    {
1274
421k
        SBW_DONE,
1275
421k
        SBW_SCALE,
1276
421k
        SBW_FROM_RENDERER
1277
421k
    } sbw_state = SBW_SCALE;
1278
1279
421k
    if ( index == GS_NO_GLYPH )
1280
0
        return 0;
1281
1282
421k
    I->use_outline = false;
1283
421k
    I->transform_outline = false;
1284
1285
421k
    if (penum == 0)
1286
0
        return_error(gs_error_undefined);
1287
1288
421k
    I->use_outline =
1289
421k
        produce_outline_char(penum_s, pbfont, alpha_bits, &log2_scale);
1290
1291
421k
    if (I->use_outline) {
1292
2.25k
        I->max_bitmap = 0;
1293
2.25k
    }
1294
419k
    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
419k
        I->max_bitmap =
1301
419k
            pbfont->dir->ccache.upper + (pbfont->dir->ccache.upper >> 1) <
1302
419k
            MAX_CCACHE_TEMP_BITMAP_BITS ? pbfont->dir->ccache.upper +
1303
419k
            (pbfont->dir->ccache.upper >> 1) : MAX_CCACHE_TEMP_BITMAP_BITS;
1304
419k
    }
1305
1306
421k
    if (pbfont->memory->gs_lib_ctx->font_dir != NULL)
1307
421k
        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
421k
    if (!SHOW_IS(penum, TEXT_DO_NONE) && !I->use_outline) {
1313
383k
        gs_currentcharmatrix(pgs, NULL, 1);     /* make char_tm valid */
1314
383k
        penum_s->fapi_log2_scale = log2_scale;
1315
383k
    }
1316
38.5k
    else {
1317
38.5k
        log2_scale.x = 0;
1318
38.5k
        log2_scale.y = 0;
1319
38.5k
    }
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
421k
    I->ff.memory = pbfont->memory;
1328
421k
    I->ff.subfont = subfont;
1329
421k
    I->ff.font_file_path = font_file_path;
1330
421k
    I->ff.client_font_data = pbfont;
1331
421k
    I->ff.client_font_data2 = pbfont;
1332
421k
    I->ff.server_font_data = pbfont->FAPI_font_data;
1333
421k
    I->ff.is_type1 = bIsType1GlyphData;
1334
421k
    I->ff.is_cid = bCID;
1335
421k
    I->ff.is_outline_font = pbfont->PaintType != 0;
1336
421k
    I->ff.metrics_only = fapi_gs_char_show_width_only(penum);
1337
1338
421k
    if (!I->ff.is_mtx_skipped)
1339
421k
        I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
1340
1341
421k
    I->ff.is_vertical = bVertical;
1342
421k
    I->ff.client_ctx_p = I->client_ctx_p;
1343
1344
421k
    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
421k
   scale = 1 << I->frac_shift;
1355
440k
retry_oversampling:
1356
440k
    if (I->face.font_id != pbfont->id ||
1357
440k
        !MTX_EQ((&I->face.ctm), ctm) ||
1358
440k
        I->face.log2_scale.x != log2_scale.x ||
1359
440k
        I->face.log2_scale.y != log2_scale.y ||
1360
440k
        I->face.align_to_pixels != align_to_pixels ||
1361
440k
        I->face.HWResolution[0] != dev->HWResolution[0] ||
1362
440k
        I->face.HWResolution[1] != dev->HWResolution[1]
1363
440k
        ) {
1364
52.4k
        gs_fapi_font_scale font_scale = { {1, 0, 0, 1, 0, 0}
1365
52.4k
        , {0, 0}
1366
52.4k
        , {1, 1}
1367
52.4k
        , true
1368
52.4k
        };
1369
1370
52.4k
        gs_matrix lctm, scale_mat, scale_ctm;
1371
52.4k
        I->face.font_id = pbfont->id;
1372
52.4k
        I->face.log2_scale = log2_scale;
1373
52.4k
        I->face.align_to_pixels = align_to_pixels;
1374
52.4k
        I->face.HWResolution[0] = dev->HWResolution[0];
1375
52.4k
        I->face.HWResolution[1] = dev->HWResolution[1];
1376
1377
52.4k
        font_scale.subpixels[0] = 1 << log2_scale.x;
1378
52.4k
        font_scale.subpixels[1] = 1 << log2_scale.y;
1379
52.4k
        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
52.4k
        lctm = *ctm;
1385
54.4k
retry_scaling:
1386
54.4k
        I->face.ctm = lctm;
1387
54.4k
        memset(&scale_ctm, 0x00, sizeof(gs_matrix));
1388
54.4k
        scale_ctm.xx = dev->HWResolution[0] / 72;
1389
54.4k
        scale_ctm.yy = dev->HWResolution[1] / 72;
1390
1391
54.4k
        if ((code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm)) < 0)
1392
0
            return code;
1393
1394
54.4k
        if ((code = gs_matrix_multiply(&lctm, &scale_ctm, &scale_mat)) < 0)  /* scale_mat ==  CTM - resolution scaling */
1395
0
            return code;
1396
1397
54.4k
        if ((code = I->get_fontmatrix(I, &scale_ctm)) < 0)
1398
0
            return code;
1399
1400
54.4k
        if ((code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm)) < 0)
1401
0
            return code;
1402
1403
54.4k
        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
54.4k
        if (((int64_t)(scale_mat.xx * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.xx * FontMatrix_div * scale + 0.5))
1407
54.4k
        ||  ((int64_t)(scale_mat.xy * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.xy * FontMatrix_div * scale + 0.5))
1408
54.4k
        ||  ((int64_t)(scale_mat.yx * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.yx * FontMatrix_div * scale + 0.5))
1409
54.4k
        ||  ((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
2.02k
            memset(&lctm, 0x00, sizeof(gs_matrix));
1418
2.02k
            lctm.xx = 256.0;
1419
2.02k
            lctm.yy = 256.0;
1420
2.02k
            I->transform_outline = true;
1421
2.02k
            I->use_outline = true;
1422
2.02k
            if ((code = gs_matrix_invert((const gs_matrix *)&lctm, &scale_ctm)) < 0)
1423
0
                 return code;
1424
2.02k
            if ((code = gs_matrix_multiply(ctm, &scale_ctm, &scale_mat)) < 0)  /* scale_mat ==  CTM - resolution scaling */
1425
0
                return code;
1426
1427
2.02k
            I->outline_mat = scale_mat;
1428
2.02k
            goto retry_scaling;
1429
2.02k
        }
1430
52.4k
        else {
1431
52.4k
            font_scale.matrix[0] =  FAPI_ROUND_TO_FRACINT(scale_mat.xx * FontMatrix_div * scale);
1432
52.4k
            font_scale.matrix[1] = -FAPI_ROUND_TO_FRACINT(scale_mat.xy * FontMatrix_div * scale);
1433
52.4k
            font_scale.matrix[2] =  FAPI_ROUND_TO_FRACINT(scale_mat.yx * FontMatrix_div * scale);
1434
52.4k
            font_scale.matrix[3] = -FAPI_ROUND_TO_FRACINT(scale_mat.yy * FontMatrix_div * scale);
1435
52.4k
            font_scale.matrix[4] =  FAPI_ROUND_TO_FRACINT(scale_mat.tx * FontMatrix_div * scale);
1436
52.4k
            font_scale.matrix[5] =  FAPI_ROUND_TO_FRACINT(scale_mat.ty * FontMatrix_div * scale);
1437
52.4k
        }
1438
1439
        /* Note: the ctm mapping here is upside down. */
1440
52.4k
        font_scale.HWResolution[0] =
1441
52.4k
            (fracint) ((double)dev->HWResolution[0] *
1442
52.4k
                       font_scale.subpixels[0] * scale);
1443
52.4k
        font_scale.HWResolution[1] =
1444
52.4k
            (fracint) ((double)dev->HWResolution[1] *
1445
52.4k
                       font_scale.subpixels[1] * scale);
1446
1447
1448
52.4k
        if ((hypot((double)font_scale.matrix[0], (double)font_scale.matrix[2])
1449
52.4k
             == 0.0
1450
52.4k
             || hypot((double)font_scale.matrix[1],
1451
51.8k
                      (double)font_scale.matrix[3]) == 0.0)) {
1452
1453
            /* If the matrix is degenerate, force a scale to 1 unit. */
1454
597
            memset(&font_scale.matrix, 0x00, sizeof(font_scale.matrix));
1455
597
            if (!font_scale.matrix[0])
1456
597
                font_scale.matrix[0] = 1;
1457
597
            if (!font_scale.matrix[3])
1458
597
                font_scale.matrix[3] = 1;
1459
597
        }
1460
1461
52.4k
        if ((code =
1462
52.4k
             gs_fapi_renderer_retcode(mem, I,
1463
52.4k
                                      I->get_scaled_font(I, &I->ff,
1464
52.4k
                                                         &font_scale, NULL,
1465
52.4k
                                                         gs_fapi_toplevel_prepared))) < 0) {
1466
1
            return code;
1467
1
        }
1468
52.4k
        pbfont->FAPI_font_data = I->ff.server_font_data;    /* Save it back to GS font. */
1469
52.4k
    }
1470
1471
440k
    cr.char_codes_count = 1;
1472
440k
    cr.char_codes[0] = index;
1473
440k
    cr.client_char_code = chr;
1474
440k
    cr.is_glyph_index = true;
1475
440k
    enc_char_name_string.data = NULL;
1476
440k
    enc_char_name_string.size = 0;
1477
1478
440k
    if (I->ff.get_glyphname_or_cid) {
1479
440k
        if ((code =
1480
440k
             I->ff.get_glyphname_or_cid(penum, pbfont, charstring, glyphname, index,
1481
440k
                                        &enc_char_name_string, font_file_path,
1482
440k
                                        &cr, bCID)) < 0)
1483
0
            return (code);
1484
440k
    }
1485
1486
    /* Compute the metrics replacement : */
1487
440k
    if (bCID && !bIsType1GlyphData) {
1488
34.9k
        gs_font_cid2 *pfcid = (gs_font_cid2 *) pbfont;
1489
34.9k
        int MetricsCount = pfcid->cidata.MetricsCount;
1490
1491
34.9k
        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
34.9k
    }
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
440k
    em_scale_x = 1.0;
1519
440k
    if (pfont->FontType == ft_TrueType) {
1520
16.6k
        gs_font_type42 *pfont42 = (gs_font_type42 *) pfont;
1521
16.6k
        em_scale_x = pfont42->data.unitsPerEm;
1522
16.6k
    }
1523
1524
440k
    if (cr.metrics_type != gs_fapi_metrics_replace && bVertical) {
1525
93
        double pwv[4];
1526
1527
93
        code =
1528
93
            I->ff.fapi_get_metrics(&I->ff, &enc_char_name_string, index, pwv,
1529
93
                                   bVertical);
1530
93
        if (code < 0)
1531
0
            return code;
1532
93
        if (code == 0 /* metricsNone */ ) {
1533
93
            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
93
            else {
1546
93
                bVertical = false;
1547
93
            }
1548
93
        }
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
93
    }
1564
440k
    if (cr.metrics_type == gs_fapi_metrics_notdef && !bVertical) {
1565
440k
        code =
1566
440k
            I->ff.fapi_get_metrics(&I->ff, &enc_char_name_string, (int)index, sbw,
1567
440k
                                   bVertical);
1568
440k
        if (code < 0)
1569
0
            return code;
1570
440k
        if (code == 0 /* metricsNone */ ) {
1571
440k
            sbw_state = SBW_FROM_RENDERER;
1572
440k
            if (pbfont->FontType == 2) {
1573
14.2k
                gs_font_type1 *pfont1 = (gs_font_type1 *) pbfont;
1574
1575
14.2k
                cr.aw_x =
1576
14.2k
                    export_shift(pfont1->data.defaultWidthX,
1577
14.2k
                                 _fixed_shift - I->frac_shift);
1578
14.2k
                cr.metrics_scale = 1000;
1579
14.2k
                cr.metrics_type = gs_fapi_metrics_add;
1580
14.2k
            }
1581
440k
        }
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
440k
    }
1593
440k
    memset(&metrics, 0x00, sizeof(metrics));
1594
    /* Take metrics from font : */
1595
440k
    if (I->ff.metrics_only) {
1596
35.5k
        code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
1597
35.5k
    }
1598
404k
    else if (I->use_outline) {
1599
22.0k
        code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
1600
22.0k
    }
1601
382k
    else {
1602
382k
        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
382k
        if (code == gs_error_VMerror) {
1607
18.3k
            I->use_outline = true;
1608
18.3k
            goto retry_oversampling;
1609
18.3k
        }
1610
364k
        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
364k
    }
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
421k
    if (code > 0) {
1626
0
        return (gs_error_unregistered);
1627
0
    }
1628
1629
421k
    if ((code = gs_fapi_renderer_retcode(mem, I, code)) < 0)
1630
451
        return code;
1631
1632
421k
    compute_em_scale(pbfont, &metrics, FontMatrix_div, &em_scale_x,
1633
421k
                     &em_scale_y);
1634
421k
    char_bbox.p.x = metrics.bbox_x0 / em_scale_x;
1635
421k
    char_bbox.p.y = metrics.bbox_y0 / em_scale_y;
1636
421k
    char_bbox.q.x = metrics.bbox_x1 / em_scale_x;
1637
421k
    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
421k
    if (pbfont->FontType != ft_MicroType && !bCID
1643
421k
        && pbfont->FontBBox.q.x > pbfont->FontBBox.p.x
1644
421k
        && pbfont->FontBBox.q.y > pbfont->FontBBox.p.y) {
1645
385k
        char_bbox.p.x = min(char_bbox.p.x, pbfont->FontBBox.p.x);
1646
385k
        char_bbox.p.y = min(char_bbox.p.y, pbfont->FontBBox.p.y);
1647
385k
        char_bbox.q.x = max(char_bbox.q.x, pbfont->FontBBox.q.x);
1648
385k
        char_bbox.q.y = max(char_bbox.q.y, pbfont->FontBBox.q.y);
1649
385k
    }
1650
1651
421k
    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
421k
    penum_s->fapi_glyph_shift.x = penum_s->fapi_glyph_shift.y = 0;
1660
421k
    if (sbw_state == SBW_FROM_RENDERER) {
1661
421k
        int can_replace_metrics;
1662
1663
421k
        if ((code =
1664
421k
             gs_fapi_renderer_retcode(mem, I,
1665
421k
                                      I->can_replace_metrics(I, &I->ff, &cr,
1666
421k
                                                             &can_replace_metrics)))
1667
421k
            < 0)
1668
0
            return code;
1669
1670
421k
        sbw[2] = metrics.escapement / em_scale_x;
1671
421k
        sbw[3] = metrics.v_escapement / em_scale_y;
1672
421k
        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
421k
    }
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
421k
    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
421k
    if (I->ff.metrics_only) {
1744
35.5k
        pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1745
35.5k
    }
1746
1747
421k
    if (pgs->in_cachedevice == CACHE_DEVICE_CACHING) {
1748
0
        sbwp = sbw;
1749
0
    }
1750
421k
    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
421k
        sbwp = NULL;
1756
1757
421k
        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
22.1k
            pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1763
22.1k
        }
1764
421k
    }
1765
1766
421k
    if (bCID) {
1767
34.2k
        code =
1768
34.2k
            I->ff.fapi_set_cache(penum, pbfont, &enc_char_name_string, index + GS_MIN_CID_GLYPH,
1769
34.2k
                                 sbw + 2, &char_bbox, sbwp, &imagenow);
1770
34.2k
    }
1771
387k
    else {
1772
387k
        code =
1773
387k
            I->ff.fapi_set_cache(penum, pbfont, &enc_char_name_string, index,
1774
387k
                                 sbw + 2, &char_bbox, sbwp, &imagenow);
1775
387k
    }
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
421k
    if (code >= 0 && imagenow == true) {
1784
421k
        code = gs_fapi_finish_render(pfont, pgs, penum, I);
1785
421k
        I->release_char_data(I);
1786
421k
    }
1787
1788
421k
    if (code != 0) {
1789
125
        if (code < 0) {
1790
            /* An error */
1791
26
            I->release_char_data(I);
1792
26
        }
1793
99
        else {
1794
            /* Callout to CDevProc, zsetcachedevice2, zfapi_finish_render. */
1795
99
        }
1796
125
    }
1797
1798
421k
    return code;
1799
421k
}
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
41.6k
{
1823
41.6k
    gs_font_base *pbfont;
1824
41.6k
    int code = 0;
1825
41.6k
    gs_fapi_server *I, **list;
1826
41.6k
    bool free_params = false;
1827
41.6k
    gs_memory_t *mem = pfont->memory;
1828
41.6k
    const char *ldecodingID = NULL;
1829
41.6k
    bool do_restart = false;
1830
1831
41.6k
    list = gs_fapi_get_server_list(mem);
1832
1833
41.6k
    if (!list) /* Should never happen */
1834
0
      return_error(gs_error_unregistered);
1835
1836
41.6k
    (*fapi_id) = NULL;
1837
1838
41.6k
    pbfont = (gs_font_base *) pfont;
1839
1840
41.6k
    I = *list;
1841
1842
41.6k
    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
41.7k
    while (I) {
1865
41.6k
        char *server_param = NULL;
1866
41.6k
        int server_param_size = 0;
1867
1868
41.6k
        code = (*get_server_param_cb) (I, (const char *)I->ig.d->subtype,
1869
41.6k
                                &server_param, &server_param_size);
1870
1871
41.6k
        if (code < 0)
1872
0
            return code;
1873
1874
41.6k
        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
41.6k
        if ((code =
1888
41.6k
             gs_fapi_renderer_retcode(mem, I,
1889
41.6k
                                      I->ensure_open(I, server_param,
1890
41.6k
                                                     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
41.6k
        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
41.6k
        pbfont->FAPI = I;       /* we need the FAPI server during this stage */
1902
41.6k
        code =
1903
41.6k
            gs_fapi_prepare_font(pfont, I, subfont, font_file_path,
1904
41.6k
                                 full_font_buf, xlatmap, &ldecodingID);
1905
41.6k
        if (code >= 0) {
1906
41.6k
            if (decodingID != NULL)
1907
40.8k
                *decodingID = (char *)ldecodingID;
1908
41.6k
            (*fapi_id) = (char *)I->ig.d->subtype;
1909
41.6k
            return 0;
1910
41.6k
        }
1911
1912
        /* renderer failed, continue search */
1913
76
        pbfont->FAPI = NULL;
1914
76
        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
76
        else {
1923
76
            I = *list;
1924
76
            list++;
1925
76
        }
1926
76
    }
1927
38
    return (code);
1928
41.6k
}
1929
1930
bool
1931
gs_fapi_available(gs_memory_t *mem, char *server)
1932
59.1k
{
1933
59.1k
    bool retval = false;
1934
1935
59.1k
    if (server) {
1936
9.15k
        gs_fapi_server *serv = NULL;
1937
1938
9.15k
        retval = (gs_fapi_find_server(mem, server, &serv, NULL) >= 0);
1939
9.15k
    }
1940
50.0k
    else {
1941
50.0k
        retval = ((mem->gs_lib_ctx->fapi_servers) != NULL) && (*(mem->gs_lib_ctx->fapi_servers) != NULL);
1942
50.0k
    }
1943
59.1k
    return (retval);
1944
59.1k
}
1945
1946
void
1947
gs_fapi_set_servers_client_data(gs_memory_t *mem, const gs_fapi_font *ff_proto, void *ctx_ptr)
1948
65.8k
{
1949
65.8k
    gs_fapi_server **servs = gs_fapi_get_server_list(mem);
1950
1951
65.8k
    if (servs) {
1952
131k
        while (*servs) {
1953
65.8k
            (*servs)->client_ctx_p = ctx_ptr;
1954
65.8k
            if (ff_proto)
1955
53.3k
                (*servs)->ff = *ff_proto;
1956
65.8k
            servs++;
1957
65.8k
        }
1958
65.8k
    }
1959
65.8k
}
1960
1961
gs_fapi_server **
1962
gs_fapi_get_server_list(gs_memory_t *mem)
1963
128k
{
1964
128k
    return (mem->gs_lib_ctx->fapi_servers);
1965
128k
}
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
20.8k
{
1971
20.8k
    gs_fapi_server **servs = gs_fapi_get_server_list(mem);
1972
20.8k
    char *server_param = NULL;
1973
20.8k
    int server_param_size = 0;
1974
20.8k
    int code = 0;
1975
20.8k
    bool free_params = false;
1976
1977
20.8k
    (*server) = NULL;
1978
1979
30.0k
    while (servs && *servs && strcmp((char *)(*servs)->ig.d->subtype, (char *)name)) {
1980
9.15k
        servs++;
1981
9.15k
    }
1982
1983
20.8k
    if (servs && *servs && get_server_param_cb) {
1984
11.7k
        code = (*get_server_param_cb) ((*servs), (char *) (*servs)->ig.d->subtype,
1985
11.7k
                                &server_param, &server_param_size);
1986
1987
11.7k
        if (code < 0)
1988
0
            return code;
1989
1990
11.7k
        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
11.7k
        code = gs_fapi_renderer_retcode(mem, (*servs),
2005
11.7k
                                 (*servs)->ensure_open((*servs),
2006
11.7k
                                                       server_param,
2007
11.7k
                                                       server_param_size));
2008
2009
11.7k
        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
11.7k
        (*server) = (*servs);
2015
11.7k
    }
2016
9.15k
    else {
2017
9.15k
        if (!servs || !(*servs)) {
2018
9.15k
            code = gs_error_invalidaccess;
2019
9.15k
        }
2020
9.15k
    }
2021
2022
2023
20.8k
    return (code);
2024
20.8k
}
2025
2026
int
2027
gs_fapi_init(gs_memory_t *mem)
2028
9.15k
{
2029
9.15k
    int code = 0;
2030
9.15k
    int i, num_servers = 0;
2031
9.15k
    gs_fapi_server **servs = NULL;
2032
9.15k
    const gs_fapi_server_init_func *gs_fapi_server_inits =
2033
9.15k
        gs_get_fapi_server_inits();
2034
2035
18.3k
    while (gs_fapi_server_inits[num_servers]) {
2036
9.15k
        num_servers++;
2037
9.15k
    }
2038
2039
9.15k
    servs =
2040
9.15k
        (gs_fapi_server **) gs_alloc_bytes_immovable(mem->non_gc_memory,
2041
9.15k
                                                     (num_servers +
2042
9.15k
                                                      1) *
2043
9.15k
                                                     sizeof(gs_fapi_server *),
2044
9.15k
                                                     "gs_fapi_init");
2045
9.15k
    if (!servs) {
2046
0
        return_error(gs_error_VMerror);
2047
0
    }
2048
2049
18.3k
    for (i = 0; i < num_servers; i++) {
2050
9.15k
        gs_fapi_server_init_func *f =
2051
9.15k
            (gs_fapi_server_init_func *) & (gs_fapi_server_inits[i]);
2052
2053
9.15k
        code = (*f) (mem, &(servs[i]));
2054
9.15k
        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
9.15k
        servs[i]->client_ctx_p = NULL;
2060
9.15k
    }
2061
2062
18.3k
    for (; i < num_servers + 1; i++) {
2063
9.15k
        servs[i] = NULL;
2064
9.15k
    }
2065
2066
9.15k
    mem->gs_lib_ctx->fapi_servers = servs;
2067
2068
9.15k
    return (code);
2069
9.15k
}
2070
2071
void
2072
gs_fapi_finit(gs_memory_t *mem)
2073
9.15k
{
2074
9.15k
    gs_fapi_server **servs = mem->gs_lib_ctx->fapi_servers;
2075
2076
18.3k
    while (servs && *servs) {
2077
9.15k
        ((*servs)->ig.d->finit) (servs);
2078
9.15k
        servs++;
2079
9.15k
    }
2080
9.15k
    gs_free_object(mem->non_gc_memory, mem->gs_lib_ctx->fapi_servers,
2081
9.15k
                   "gs_fapi_finit: mem->gs_lib_ctx->fapi_servers");
2082
9.15k
    mem->gs_lib_ctx->fapi_servers = NULL;
2083
9.15k
}