Coverage Report

Created: 2025-06-10 07:27

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