Coverage Report

Created: 2025-06-10 06:58

/src/ghostpdl/base/gxfapi.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
#include "memory_.h"
18
19
#include "gsmemory.h"
20
#include "gserrors.h"
21
#include "gxdevice.h"
22
#include "gxfont.h"
23
#include "gxfont1.h"
24
#include "gxpath.h"
25
#include "gxfcache.h"
26
#include "gxchrout.h"
27
#include "gximask.h"
28
#include "gscoord.h"
29
#include "gspaint.h"
30
#include "gspath.h"
31
#include "gzstate.h"
32
#include "gxfcid.h"
33
#include "gxchar.h"             /* for st_gs_show_enum and MAX_CCACHE_TEMP_BITMAP_BITS */
34
#include "gdebug.h"
35
#include "gsimage.h"
36
#include "gsbittab.h"
37
#include "gzpath.h"
38
#include "gxdevsop.h"
39
40
#include "gxfapi.h"
41
42
521k
#define FAPI_ROUND(v) (v >= 0 ? v + 0.5 : v - 0.5)
43
521k
#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
3.18M
{
52
3.18M
    if (rc == 0)
53
3.17M
        return 0;
54
3.75k
    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
3.75k
    return rc < 0 ? rc : gs_error_invalidfont;
60
3.18M
}
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
42.4M
{
75
42.4M
    return (n > 0 ? (x << n) : (x >> -n));
76
42.4M
}
77
78
static inline int
79
export_shift(int x, int n)
80
33.6k
{
81
33.6k
    return (n > 0 ? (x >> n) : (x << -n));
82
33.6k
}
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
976k
{
93
976k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
94
95
976k
    if (olh->need_close == true) {
96
911k
        olh->need_close = false;
97
911k
        I->gs_error = gx_path_close_subpath_notes(olh->path, 0);
98
911k
    }
99
976k
    return (I->gs_error);
100
976k
}
101
102
static int
103
add_move(gs_fapi_path *I, int64_t x, int64_t y)
104
922k
{
105
922k
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
106
107
922k
    x = import_shift(x, I->shift);
108
922k
    y = -import_shift(y, I->shift);
109
922k
    if (olh->fserver->transform_outline) {
110
2.62k
        gs_point pt;
111
2.62k
        I->gs_error = gs_distance_transform((double)fixed2float((float)x), (double)fixed2float((float)y), &olh->fserver->outline_mat, &pt);
112
2.62k
        if (I->gs_error < 0)
113
0
            return I->gs_error;
114
2.62k
        x = float2fixed(pt.x);
115
2.62k
        y = float2fixed(pt.y);
116
2.62k
    }
117
922k
    x += olh->x0;
118
922k
    y += olh->y0;
119
120
922k
    if (x > (int64_t) max_coord_fixed || x < (int64_t) min_coord_fixed
121
922k
     || y > (int64_t) max_coord_fixed || y < (int64_t) min_coord_fixed) {
122
3.40k
         I->gs_error = gs_error_undefinedresult;
123
3.40k
    }
124
918k
    else {
125
126
918k
        if (olh->need_close && olh->close_path)
127
302k
            if ((I->gs_error = add_closepath(I)) < 0)
128
0
                return (I->gs_error);
129
918k
        olh->need_close = false;
130
131
/*        dprintf2("%f %f moveto\n", fixed2float(x), fixed2float(y)); */
132
918k
        I->gs_error = gx_path_add_point(olh->path, (fixed) x, (fixed) y);
133
918k
    }
134
922k
    return (I->gs_error);
135
922k
}
136
137
static int
138
add_line(gs_fapi_path *I, int64_t x, int64_t y)
139
3.93M
{
140
3.93M
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
141
142
3.93M
    x = import_shift(x, I->shift);
143
3.93M
    y = -import_shift(y, I->shift);
144
3.93M
    if (olh->fserver->transform_outline) {
145
895
        gs_point pt;
146
895
        I->gs_error = gs_distance_transform((double)fixed2float((float)x), (double)fixed2float((float)y), &olh->fserver->outline_mat, &pt);
147
895
        if (I->gs_error < 0)
148
0
            return I->gs_error;
149
895
        x = float2fixed(pt.x);
150
895
        y = float2fixed(pt.y);
151
895
    }
152
3.93M
    x += olh->x0;
153
3.93M
    y += olh->y0;
154
155
3.93M
    if (x > (int64_t) max_coord_fixed || x < (int64_t) min_coord_fixed
156
3.93M
     || y > (int64_t) max_coord_fixed || y < (int64_t) min_coord_fixed) {
157
114
         I->gs_error = gs_error_undefinedresult;
158
114
    }
159
3.93M
    else {
160
3.93M
        olh->need_close = true;
161
162
/*        dprintf2("%f %f lineto\n", fixed2float(x), fixed2float(y)); */
163
3.93M
        I->gs_error = gx_path_add_line_notes(olh->path, (fixed) x, (fixed) y, 0);
164
3.93M
    }
165
3.93M
    return (I->gs_error);
166
3.93M
}
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
5.46M
{
172
5.46M
    gs_fapi_outline_handler *olh = (gs_fapi_outline_handler *) I->olh;
173
174
5.46M
    x0 = import_shift(x0, I->shift);
175
5.46M
    y0 = -import_shift(y0, I->shift);
176
5.46M
    x1 = import_shift(x1, I->shift);
177
5.46M
    y1 = -import_shift(y1, I->shift);
178
5.46M
    x2 = import_shift(x2, I->shift);
179
5.46M
    y2 = -import_shift(y2, I->shift);
180
181
5.46M
    if (olh->fserver->transform_outline) {
182
392
        gs_point pt;
183
392
        I->gs_error = gs_distance_transform((double)fixed2float((float)x0), (double)fixed2float((float)y0), &olh->fserver->outline_mat, &pt);
184
392
        if (I->gs_error < 0)
185
0
            return I->gs_error;
186
392
        x0 = float2fixed(pt.x);
187
392
        y0 = float2fixed(pt.y);
188
392
        I->gs_error = gs_distance_transform((double)fixed2float((float)x1), (double)fixed2float((float)y1), &olh->fserver->outline_mat, &pt);
189
392
        if (I->gs_error < 0)
190
0
            return I->gs_error;
191
392
        x1 = float2fixed(pt.x);
192
392
        y1 = float2fixed(pt.y);
193
392
        I->gs_error = gs_distance_transform((double)fixed2float((float)x2), (double)fixed2float((float)y2), &olh->fserver->outline_mat, &pt);
194
392
        if (I->gs_error < 0)
195
0
            return I->gs_error;
196
392
        x2 = float2fixed(pt.x);
197
392
        y2 = float2fixed(pt.y);
198
392
    }
199
5.46M
    x0 += olh->x0;
200
5.46M
    y0 += olh->y0;
201
5.46M
    x1 += olh->x0;
202
5.46M
    y1 += olh->y0;
203
5.46M
    x2 += olh->x0;
204
5.46M
    y2 += olh->y0;
205
206
5.46M
    if (x0 > (int64_t) max_coord_fixed || x0 < (int64_t) min_coord_fixed
207
5.46M
     || y0 > (int64_t) max_coord_fixed || y0 < (int64_t) min_coord_fixed
208
5.46M
     || x1 > (int64_t) max_coord_fixed || x1 < (int64_t) min_coord_fixed
209
5.46M
     || y1 > (int64_t) max_coord_fixed || y1 < (int64_t) min_coord_fixed
210
5.46M
     || x2 > (int64_t) max_coord_fixed || x2 < (int64_t) min_coord_fixed
211
5.46M
     || y2 > (int64_t) max_coord_fixed || y2 < (int64_t) min_coord_fixed)
212
37
    {
213
37
        I->gs_error = gs_error_undefinedresult;
214
37
    }
215
5.46M
    else {
216
5.46M
        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
5.46M
        I->gs_error = gx_path_add_curve_notes(olh->path, (fixed) x0, (fixed) y0, (fixed) x1, (fixed) y1, (fixed) x2, (fixed) y2, 0);
220
5.46M
    }
221
5.46M
    return (I->gs_error);
222
5.46M
}
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
1.14M
{
230
1.14M
    if (!ff->is_type1 && ff->is_cid) {
231
78.6k
        gs_font_cid2 *pfcid = (gs_font_cid2 *) ff->client_font_data;
232
233
78.6k
        return (pfcid->cidata.MetricsCount);
234
78.6k
    }
235
1.06M
    return 0;
236
1.14M
}
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
1.07M
{
249
1.07M
    if (!gs_text_is_width_only(penum))
250
1.02M
        return false;
251
56.4k
    switch (penum->orig_font->FontType) {
252
50.3k
        case ft_encrypted:
253
50.3k
        case ft_encrypted2:
254
50.3k
        case ft_CID_encrypted:
255
50.3k
        case ft_CID_TrueType:
256
50.3k
        case ft_CID_bitmap:
257
52.6k
        case ft_TrueType:
258
52.6k
            return true;
259
3.80k
        default:
260
3.80k
            return false;
261
56.4k
    }
262
56.4k
}
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
1.07M
{
274
1.07M
    gx_device *dev = gs_currentdevice_inline(pgs);
275
276
1.07M
    return ((!gs_color_writes_pure(pgs)) && dev_proc(dev, dev_spec_op)(dev, gxdso_supports_pattern_transparency, NULL, 0));
277
1.07M
}
278
279
static inline bool
280
recreate_multiple_master(gs_font_base *pbfont)
281
1.07M
{
282
1.07M
    bool r = false;
283
1.07M
    gs_fapi_server *I = pbfont->FAPI;
284
1.07M
    bool changed = false;
285
286
1.07M
    if (I && I->face.font_id != gs_no_id &&
287
1.07M
        (pbfont->FontType == ft_encrypted
288
1.03M
        || pbfont->FontType == ft_encrypted2)) {
289
903k
        gs_font_type1 *pfont1 = (gs_font_type1 *) pbfont;
290
903k
        if (pfont1->data.WeightVector.count != 0
291
903k
            && I->face.WeightVector.count != pfont1->data.WeightVector.count) {
292
0
            changed = true;
293
0
        }
294
903k
        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
903k
        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
903k
    }
306
1.07M
    return r;
307
1.07M
}
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
1.07M
{
314
1.07M
    gs_gstate *pgs = (gs_gstate *) penum_s->pgs;
315
316
1.07M
    log2_scale->x = 0;
317
1.07M
    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
1.07M
    gx_compute_text_oversampling(penum_s, (gs_font *) pbfont, abits,
326
1.07M
                                 log2_scale);
327
328
1.07M
    return (pgs->in_charpath || pbfont->PaintType != 0 ||
329
1.07M
            (pgs->in_cachedevice != CACHE_DEVICE_CACHING
330
1.07M
             && using_transparency_pattern((gs_gstate *) penum_s->pgs))
331
1.07M
            || (pgs->in_cachedevice != CACHE_DEVICE_CACHING
332
407k
                && (log2_scale->x > 0 || log2_scale->y > 0))
333
1.07M
            || (pgs->in_cachedevice != CACHE_DEVICE_CACHING && abits > 1));
334
1.07M
}
335
336
static inline void
337
gs_fapi_release_typeface(gs_fapi_server *I, void **server_font_data)
338
65.8k
{
339
65.8k
    I->release_typeface(I, *server_font_data);
340
65.8k
    I->face.font_id = gs_no_id;
341
65.8k
    if (I->ff.server_font_data == *server_font_data)
342
17.9k
        I->ff.server_font_data = 0;
343
65.8k
    *server_font_data = 0;
344
65.8k
}
345
346
static int
347
notify_remove_font(void *proc_data, void *event_data)
348
66.5k
{                               /* gs_font_finalize passes event_data == NULL, so check it here. */
349
66.5k
    if (event_data == NULL) {
350
66.5k
        gs_font_base *pbfont = proc_data;
351
66.5k
        gs_fapi_server *I = pbfont->FAPI;
352
353
66.5k
        if (pbfont->FAPI_font_data != 0) {
354
65.8k
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
355
65.8k
        }
356
66.5k
    }
357
66.5k
    return 0;
358
66.5k
}
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
66.5k
{                               /* 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
66.5k
    gs_memory_t *mem = pfont->memory;
386
66.5k
    gs_font_base *pbfont = (gs_font_base *)pfont;
387
66.5k
    int code, bbox_set = 0;
388
66.5k
    int BBox[4], scale;
389
66.5k
    int units[2];
390
66.5k
    double size;
391
66.5k
    gs_fapi_font_scale font_scale =
392
66.5k
        { {1, 0, 0, 1, 0, 0}, {0, 0}, {1, 1}, true };
393
394
66.5k
    scale = 1 << I->frac_shift;
395
66.5k
    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
66.5k
    if (size < 1000)
400
66.1k
        size = 1000;
401
402
66.5k
    font_scale.matrix[0] = font_scale.matrix[3] = (int)(size * scale + 0.5);
403
404
66.5k
    font_scale.HWResolution[0] = (fracint) (72 * scale);
405
66.5k
    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
66.5k
    I->ff.subfont = subfont;
411
66.5k
    I->ff.font_file_path = font_file_path;
412
66.5k
    I->ff.is_type1 = FAPI_ISTYPE1GLYPHDATA(pbfont);
413
66.5k
    I->ff.is_vertical = (pbfont->WMode != 0);
414
66.5k
    I->ff.memory = mem;
415
66.5k
    I->ff.client_ctx_p = I->client_ctx_p;
416
66.5k
    I->ff.client_font_data = pbfont;
417
66.5k
    I->ff.client_font_data2 = pbfont;
418
66.5k
    I->ff.server_font_data = pbfont->FAPI_font_data;    /* Possibly pass it from zFAPIpassfont. */
419
66.5k
    if (full_font_buf) {
420
63.1k
        I->ff.full_font_buf = (char *)full_font_buf->data;
421
63.1k
        I->ff.full_font_buf_len = full_font_buf->size;
422
63.1k
    }
423
3.39k
    else {
424
3.39k
        I->ff.full_font_buf = NULL;
425
3.39k
        I->ff.full_font_buf_len = 0;
426
3.39k
    }
427
66.5k
    I->ff.is_cid = FAPI_ISCIDFONT(pbfont);
428
66.5k
    I->ff.is_outline_font = pbfont->PaintType != 0;
429
430
66.5k
    if (!I->ff.is_mtx_skipped)
431
66.5k
        I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
432
433
66.5k
    if ((code = gs_fapi_renderer_retcode(mem, I, I->get_scaled_font(I, &I->ff,
434
66.5k
                                                                    (const
435
66.5k
                                                                     gs_fapi_font_scale
436
66.5k
                                                                     *)
437
66.5k
                                                                    &font_scale, xlatmap, gs_fapi_toplevel_begin)))
438
66.5k
        < 0)
439
136
        return code;
440
66.4k
    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
66.4k
    if (I->ff.server_font_data != 0
448
66.4k
        && (font_file_path != NULL || full_font_buf != NULL)) {
449
62.9k
        if ((code =
450
62.9k
             gs_fapi_renderer_retcode(mem, I,
451
62.9k
                                      I->get_font_bbox(I, &I->ff,
452
62.9k
                                                       BBox, units))) < 0) {
453
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
454
0
            return code;
455
0
        }
456
        /* Refine FontBBox : */
457
62.9k
        pbfont->FontBBox.p.x = ((double)BBox[0] / units[0]);
458
62.9k
        pbfont->FontBBox.p.y = ((double)BBox[1] / units[1]);
459
62.9k
        pbfont->FontBBox.q.x = ((double)BBox[2] / units[0]);
460
62.9k
        pbfont->FontBBox.q.y = ((double)BBox[3] / units[1]);
461
462
62.9k
        bbox_set = 1;
463
62.9k
    }
464
465
66.4k
    if (xlatmap != NULL && pbfont->FAPI_font_data != NULL) {
466
346
        if ((code =
467
346
             gs_fapi_renderer_retcode(mem, I,
468
346
                                      I->get_decodingID(I, &I->ff,
469
346
                                                        decodingID))) < 0) {
470
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
471
0
            return code;
472
0
        }
473
346
    }
474
475
    /* Prepare descendant fonts : */
476
66.4k
    if (font_file_path == NULL && I->ff.is_type1 && I->ff.is_cid) {     /* Renderers should expect same condition. */
477
159
        gs_font_cid0 *pfcid = (gs_font_cid0 *) pbfont;
478
159
        gs_font_type1 **FDArray = pfcid->cidata.FDArray;
479
159
        int i, n = pfcid->cidata.FDArray_size;
480
481
159
        I->ff.is_type1 = true;
482
159
        I->ff.is_vertical = false;      /* A subfont may be shared with another fonts. */
483
159
        I->ff.memory = mem;
484
159
        I->ff.client_ctx_p = I->client_ctx_p;
485
483
        for (i = 0; i < n; i++) {
486
326
            gs_font_type1 *pbfont1 = FDArray[i];
487
326
            int BBox_temp[4];
488
326
            int units_temp[2];
489
490
326
            pbfont1->FontBBox = pbfont->FontBBox;       /* Inherit FontBBox from the type 9 font. */
491
492
326
            I->ff.client_font_data = pbfont1;
493
326
            pbfont1->FAPI = pbfont->FAPI;
494
326
            I->ff.client_font_data2 = pbfont1;
495
326
            I->ff.server_font_data = pbfont1->FAPI_font_data;
496
326
            I->ff.is_cid = true;
497
326
            I->ff.is_outline_font = pbfont1->PaintType != 0;
498
326
            if (!I->ff.is_mtx_skipped)
499
326
                I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
500
326
            I->ff.subfont = 0;
501
326
            if ((code =
502
326
                 gs_fapi_renderer_retcode(mem, I,
503
326
                                          I->get_scaled_font(I, &I->ff,
504
326
                                                             (const
505
326
                                                              gs_fapi_font_scale
506
326
                                                              *)&font_scale,
507
326
                                                             NULL, i))) < 0) {
508
2
                break;
509
2
            }
510
511
324
            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
324
            if ((code =
514
324
                 gs_fapi_renderer_retcode(mem, I,
515
324
                                          I->get_font_bbox(I, &I->ff,
516
324
                                                           BBox_temp, units_temp))) < 0) {
517
0
                break;
518
0
            }
519
324
            code = gs_notify_register(&pbfont1->notify_list, notify_remove_font, pbfont1);
520
324
            if (code < 0) {
521
0
                emprintf(mem,
522
0
                         "Ignoring gs_notify_register() failure for FAPI font.....");
523
0
            }
524
324
        }
525
159
        if (i == n) {
526
157
            code =
527
157
                gs_fapi_renderer_retcode(mem, I,
528
157
                                         I->get_scaled_font(I, &I->ff,
529
157
                                                            (const
530
157
                                                             gs_fapi_font_scale
531
157
                                                             *)&font_scale,
532
157
                                                            NULL,
533
157
                                                            gs_fapi_toplevel_complete));
534
157
            if (code >= 0)
535
157
                return bbox_set;        /* Full success. */
536
157
        }
537
        /* Fail, release server's font data : */
538
4
        for (i = 0; i < n; i++) {
539
2
            gs_font_type1 *pbfont1 = FDArray[i];
540
541
2
            if (pbfont1->FAPI_font_data != NULL)
542
0
                gs_fapi_release_typeface(I, &pbfont1->FAPI_font_data);
543
2
        }
544
545
2
        if (pbfont->FAPI_font_data != NULL) {
546
0
            gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
547
0
        }
548
2
        return_error(gs_error_invalidfont);
549
159
    }
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
66.2k
    code = gs_fapi_renderer_retcode(mem, I, I->get_scaled_font(I, &I->ff,
555
66.2k
                                                               (const
556
66.2k
                                                                gs_fapi_font_scale
557
66.2k
                                                                *)&font_scale,
558
66.2k
                                                               xlatmap,
559
66.2k
                                                               gs_fapi_toplevel_complete));
560
66.2k
    if (code < 0) {
561
0
        gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
562
0
        return code;
563
0
    }
564
66.2k
    code =
565
66.2k
        gs_notify_register(&pbfont->notify_list, notify_remove_font, pbfont);
566
66.2k
    if (code < 0) {
567
0
        gs_fapi_release_typeface(I, &pbfont->FAPI_font_data);
568
0
        return code;
569
0
    }
570
571
66.2k
    return bbox_set;
572
66.2k
}
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
677k
{
579
677k
    gs_fapi_path path_interface = path_interface_stub;
580
677k
    gs_fapi_outline_handler olh;
581
677k
    int code = 0;
582
677k
    gs_gstate *pgs = penum_s->pgs;
583
677k
    struct gx_path_s path1;
584
585
677k
    (void)gx_path_init_local(&path1, mem);
586
587
677k
    olh.fserver = I;
588
677k
    olh.path = &path1;
589
677k
    olh.x0 = pgs->ctm.tx_fixed - float2fixed(penum_s->fapi_glyph_shift.x);
590
677k
    olh.y0 = pgs->ctm.ty_fixed - float2fixed(penum_s->fapi_glyph_shift.y);
591
677k
    olh.close_path = close_path;
592
677k
    olh.need_close = false;
593
677k
    path_interface.olh = &olh;
594
677k
    path_interface.shift = import_shift_v;
595
677k
    if ((code =
596
677k
         gs_fapi_renderer_retcode(mem, I,
597
677k
                                  I->get_char_outline(I,
598
677k
                                                      &path_interface))) < 0
599
677k
        || path_interface.gs_error != 0) {
600
3.55k
        if (path_interface.gs_error != 0) {
601
3.55k
            code = path_interface.gs_error;
602
3.55k
            goto done;
603
3.55k
        }
604
0
        else {
605
0
            goto done;
606
0
        }
607
3.55k
    }
608
674k
    if (olh.need_close && olh.close_path)
609
0
        if ((code = add_closepath(&path_interface)) < 0)
610
0
            goto done;
611
674k
    code = gx_path_copy(&path1, path);
612
677k
done:
613
677k
    code = code >= 0 || code == gs_error_undefinedresult ? 0 : code;
614
677k
    gx_path_free(&path1, "outline_char");
615
677k
    return code;
616
674k
}
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
1.07M
{                               /* optimize : move this stuff to FAPI_refine_font */
623
1.07M
    gs_matrix mat;
624
1.07M
    gs_matrix *m = &mat;
625
1.07M
    int rounding_x, rounding_y; /* Striking out the 'float' representation error in FontMatrix. */
626
1.07M
    double sx, sy;
627
1.07M
    gs_fapi_server *I = pbfont->FAPI;
628
629
1.07M
#if 1
630
1.07M
    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
1.07M
    if (m->xx == 0 && m->xy == 0 && m->yx == 0 && m->yy == 0)
638
0
        m = &pbfont->base->FontMatrix;
639
1.07M
    sx = hypot(m->xx, m->xy) * metrics->em_x / FontMatrix_div;
640
1.07M
    sy = hypot(m->yx, m->yy) * metrics->em_y / FontMatrix_div;
641
1.07M
    rounding_x = (int)(0x00800000 / sx);
642
1.07M
    rounding_y = (int)(0x00800000 / sy);
643
1.07M
    *em_scale_x = (int)(sx * rounding_x + 0.5) / (double)rounding_x;
644
1.07M
    *em_scale_y = (int)(sy * rounding_y + 0.5) / (double)rounding_y;
645
1.07M
}
646
647
static int
648
fapi_copy_mono(gx_device *dev1, gs_fapi_raster *rast, int dx, int dy)
649
336k
{
650
336k
    int line_step = bitmap_raster(rast->width), code;
651
652
336k
    if (rast->line_step >= line_step) {
653
1.44k
        return dev_proc(dev1, copy_mono) (dev1, rast->p, 0, rast->line_step,
654
1.44k
                                          0, dx, dy, rast->width,
655
1.44k
                                          rast->height, 0, 1);
656
1.44k
    }
657
334k
    else {                      /* bitmap data needs to be aligned, make the aligned copy : */
658
334k
        byte *p = gs_alloc_byte_array(dev1->memory, rast->height, line_step,
659
334k
                                      "fapi_copy_mono");
660
334k
        byte *q = p, *r = rast->p, *pe;
661
662
334k
        if (p == NULL)
663
0
            return_error(gs_error_VMerror);
664
334k
        pe = p + rast->height * line_step;
665
5.97M
        for (; q < pe; q += line_step, r += rast->line_step) {
666
5.63M
            memcpy(q, r, rast->line_step);
667
5.63M
            memset(q + rast->line_step, 0, line_step - rast->line_step);
668
5.63M
        }
669
334k
        code =
670
334k
            dev_proc(dev1, copy_mono) (dev1, p, 0, line_step, 0, dx, dy,
671
334k
                                       rast->width, rast->height, 0, 1);
672
334k
        gs_free_object(dev1->memory, p, "fapi_copy_mono");
673
334k
        return code;
674
334k
    }
675
336k
}
676
677
/*
678
 * For PCL/PXL pseudo-bolding, we have to "smear" a bitmap horizontally and
679
 * vertically by ORing together a rectangle of bits below and to the left of
680
 * each output bit.  We do this separately for horizontal and vertical
681
 * smearing.  Eventually, we will replace the current procedure, which takes
682
 * time proportional to W * H * (N + log2(N)), with one that is only
683
 * proportional to N (but takes W * N additional buffer space).
684
 */
685
686
/* Allocate the line buffer for bolding.  We need 2 + bold scan lines. */
687
static byte *
688
alloc_bold_lines(gs_memory_t *mem, uint width, int bold, client_name_t cname)
689
0
{
690
0
    return gs_alloc_byte_array(mem, 2 + bold, bitmap_raster(width + bold), cname);
691
0
}
692
693
/* Merge one (aligned) scan line into another, for vertical smearing. */
694
void
695
gx_fapi_bits_merge(byte *dest, const byte *src, uint nbytes)
696
0
{
697
0
        long *dp = (long *)dest;
698
0
        const long *sp = (const long *)src;
699
0
        uint n = (nbytes + sizeof(long) - 1) >> ARCH_LOG2_SIZEOF_LONG;
700
701
0
        for ( ; n >= 4; sp += 4, dp += 4, n -= 4 ) {
702
0
            dp[0] |= sp[0];
703
0
            dp[1] |= sp[1];
704
0
            dp[2] |= sp[2];
705
0
            dp[3] |= sp[3];
706
0
        }
707
0
        for ( ; n; ++sp, ++dp, --n ) {
708
0
            *dp |= *sp;
709
0
        }
710
0
}
711
712
/* Smear a scan line horizontally.  Note that the output is wider than */
713
/* the input by the amount of bolding (smear_width). */
714
void
715
gx_fapi_bits_smear_horizontally(byte *dest, const byte *src, uint width, uint smear_width)
716
0
{
717
0
        uint32_t bits_on = 0;
718
0
        const byte *sp = src;
719
0
        uint sbyte = *sp;
720
0
        byte *dp = dest;
721
0
        uint dbyte = sbyte;
722
0
        uint sdmask = 0x80;
723
0
        const byte *zp = src;
724
0
        uint zmask = 0x80;
725
0
        uint i = 0;
726
0
        uint stop;
727
728
        /* Process the first smear_width bits. */
729
0
        stop = min(smear_width, width);
730
731
0
        for ( ; i < stop; ++i ) {
732
0
            if ( sbyte & sdmask ) {
733
0
              bits_on++;
734
0
            }
735
0
            else if ( bits_on ) {
736
0
              dbyte |= sdmask;
737
0
            }
738
0
            if ( (sdmask >>= 1) == 0 ) {
739
0
                sdmask = 0x80;
740
0
                *dp++ = dbyte;
741
0
                dbyte = sbyte = *++sp;
742
0
            }
743
0
        }
744
745
        /* Process all but the last smear_width bits. */
746
0
        for ( ; i < width; ++i ) {
747
0
            if ( sbyte & sdmask ) {
748
                /* In practice, bits_on should never overflow,
749
                   but if it doesn, handle it gracefully
750
                 */
751
0
                bits_on = (uint32_t)(((uint64_t)bits_on + 1) & 0xffffffff);
752
0
            }
753
0
            else if ( bits_on ) {
754
0
                dbyte |= sdmask;
755
0
            }
756
0
            if ( *zp & zmask && bits_on > 0) {
757
0
                --bits_on;
758
0
            }
759
0
            if ( (sdmask >>= 1) == 0 ) {
760
0
                sdmask = 0x80;
761
0
                *dp++ = dbyte;
762
0
on:             switch ( (dbyte = sbyte = *++sp) ) {
763
0
                  case 0xff:
764
0
                    if ( width - i <= 8 )
765
0
                        break;
766
0
                    *dp++ = 0xff;
767
0
                    bits_on += 8 - byte_count_bits[(*zp & (zmask - 1)) + (zp[1] & -(int)zmask)];
768
0
                    ++zp;
769
0
                    i += 8;
770
0
                    goto on;
771
0
                  case 0:
772
0
                    if ( bits_on || width - i <= 8 )
773
0
                      break;
774
0
                    *dp++ = 0;
775
                    /* We know there can't be any bits to be zeroed, */
776
                    /* because bits_on can't go negative. */
777
0
                    ++zp;
778
0
                    i += 8;
779
0
                    goto on;
780
0
                  default:
781
0
                    ;
782
0
                }
783
0
            }
784
0
            if ( (zmask >>= 1) == 0 ) {
785
0
              zmask = 0x80;
786
0
              ++zp;
787
0
            }
788
0
        }
789
790
        /* Process the last smear_width bits. */
791
        /****** WRONG IF width < smear_width ******/
792
0
        stop = width + smear_width;
793
794
0
        for ( ; i < stop; ++i ) {
795
0
            if ( bits_on ) {
796
0
                dbyte |= sdmask;
797
0
            }
798
0
            if ( (sdmask >>= 1) == 0 ) {
799
0
                sdmask = 0x80;
800
0
                *dp++ = dbyte;
801
0
                dbyte = 0;
802
0
            }
803
0
            if ( *zp & zmask && bits_on > 0) {
804
0
                --bits_on;
805
0
            }
806
0
            if ( (zmask >>= 1) == 0 ) {
807
0
                zmask = 0x80;
808
0
                ++zp;
809
0
            }
810
0
        }
811
812
0
        if ( sdmask != 0x80 ) {
813
0
          *dp = dbyte;
814
0
        }
815
0
}
816
817
static const int frac_pixel_shift = 4;
818
819
/* NOTE: fapi_image_uncached_glyph() doesn't check various paramters: it assumes fapi_finish_render_aux()
820
 * has done so: if it gets called from another function, the function must either do all the parameter
821
 * validation, or fapi_image_uncached_glyph() must be changed to include the validation.
822
 */
823
static int
824
fapi_image_uncached_glyph(gs_font *pfont, gs_gstate *pgs, gs_show_enum *penum,
825
                          gs_fapi_raster *rast, const int import_shift_v)
826
10.5k
{
827
10.5k
    gx_device *dev = penum->dev;
828
10.5k
    gs_gstate *penum_pgs = (gs_gstate *) penum->pgs;
829
10.5k
    int code;
830
10.5k
    const gx_clip_path *pcpath = pgs->clip_path;
831
10.5k
    const gx_drawing_color *pdcolor = gs_currentdevicecolor_inline(penum->pgs);
832
10.5k
    int rast_orig_x = rast->orig_x;
833
10.5k
    int rast_orig_y = -rast->orig_y;
834
10.5k
    gs_font_base *pbfont = (gs_font_base *)pfont;
835
10.5k
    gs_fapi_server *I = pbfont->FAPI;
836
837
10.5k
    extern_st(st_gs_show_enum);
838
839
10.5k
    byte *r = rast->p;
840
10.5k
    byte *src, *dst;
841
10.5k
    int h, padbytes, cpbytes, dstr = bitmap_raster(rast->width);
842
10.5k
    int sstr = rast->line_step;
843
844
10.5k
    double dx = penum_pgs->ctm.tx + (double)rast_orig_x / (1 << frac_pixel_shift) + 0.5;
845
10.5k
    double dy = penum_pgs->ctm.ty + (double)rast_orig_y / (1 << frac_pixel_shift) + 0.5;
846
847
    /* we can only safely use the gx_image_fill_masked() "shortcut" if we're drawing
848
     * a "simple" colour, rather than a pattern.
849
     */
850
10.5k
    if (gs_color_writes_pure(penum_pgs) && I->ff.embolden == 0.0) {
851
3.81k
        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
2.84k
            r = gs_alloc_bytes(penum->memory, (size_t)dstr * rast->height,
865
2.84k
                               "fapi_finish_render_aux");
866
2.84k
            if (!r) {
867
0
                return_error(gs_error_VMerror);
868
0
            }
869
870
2.84k
            cpbytes = sstr < dstr ? sstr : dstr;
871
2.84k
            padbytes = dstr - cpbytes;
872
2.84k
            h = rast->height;
873
2.84k
            src = rast->p;
874
2.84k
            dst = r;
875
2.84k
            if (padbytes > 0) {
876
162k
                while (h-- > 0) {
877
159k
                    memcpy(dst, src, cpbytes);
878
159k
                    memset(dst + cpbytes, 0, padbytes);
879
159k
                    src += sstr;
880
159k
                    dst += dstr;
881
159k
                }
882
2.84k
            }
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
2.84k
        }
891
892
3.81k
        if (gs_object_type(penum->memory, penum) == &st_gs_show_enum) {
893
3.81k
            dx += penum->fapi_glyph_shift.x;
894
3.81k
            dy += penum->fapi_glyph_shift.y;
895
3.81k
        }
896
        /* Processing an image object operation, but this may be for a text object */
897
3.81k
        ensure_tag_is_set(pgs, pgs->device, GS_TEXT_TAG); /* NB: may unset_dev_color */
898
3.81k
        code = gx_set_dev_color(pgs);
899
3.81k
        if (code != 0)
900
0
            return code;
901
3.81k
        code = gs_gstate_color_load(pgs);
902
3.81k
        if (code < 0)
903
0
            return code;
904
905
3.81k
        code = gx_image_fill_masked(dev, r, 0, dstr, gx_no_bitmap_id,
906
3.81k
                                    (int)dx, (int)dy,
907
3.81k
                                    rast->width, rast->height,
908
3.81k
                                    pdcolor, 1, rop3_default, pcpath);
909
3.81k
        if (rast->p != r) {
910
2.84k
            gs_free_object(penum->memory, r, "fapi_finish_render_aux");
911
2.84k
        }
912
3.81k
    }
913
6.76k
    else {
914
6.76k
        gs_memory_t *mem = penum->memory->non_gc_memory;
915
6.76k
        gs_image_enum *pie;
916
6.76k
        gs_image_t image;
917
6.76k
        int iy, nbytes;
918
6.76k
        uint used;
919
6.76k
        int code1;
920
6.76k
        int w, h;
921
6.76k
        int x = (int)dx;
922
6.76k
        int y = (int)dy;
923
6.76k
        uint bold = 0;
924
6.76k
        byte *bold_lines = NULL;
925
6.76k
        byte *line = NULL;
926
6.76k
        int ascent = 0;
927
928
6.76k
        pie = gs_image_enum_alloc(mem, "image_char(image_enum)");
929
6.76k
        if (!pie) {
930
0
            return_error(gs_error_VMerror);
931
0
        }
932
933
6.76k
        w = rast->width;
934
6.76k
        h = rast->height;
935
6.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
6.76k
        gs_image_t_init_mask(&image, true);
954
6.76k
        gs_make_translation((double) - x, (double) (- y + ascent), &image.ImageMatrix);
955
6.76k
        gs_matrix_multiply(&ctm_only(penum_pgs), &image.ImageMatrix, &image.ImageMatrix);
956
6.76k
        image.Width = w + bold;
957
6.76k
        image.Height = h + bold;
958
6.76k
        image.adjust = false;
959
6.76k
        code = gs_image_init(pie, &image, false, true, penum_pgs);
960
6.76k
        nbytes = (rast->width + 7) >> 3;
961
962
6.76k
        switch (code) {
963
48
            case 1:            /* empty image */
964
48
                code = 0;
965
48
            default:
966
48
                break;
967
6.71k
            case 0:
968
6.71k
                if (bold == 0) {
969
868k
                    for (iy = 0; iy < h && code >= 0; iy++, r += sstr) {
970
861k
                        code = gs_image_next(pie, r, nbytes, &used);
971
861k
                    }
972
6.71k
                }
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
6.76k
#undef merged_line
1029
6.76k
        }
1030
1031
6.76k
        if (bold_lines)
1032
0
            gs_free_object(pgs->memory, bold_lines, "fapi_image_uncached_glyph(bold_lines)");
1033
1034
6.76k
        if (line)
1035
0
            gs_free_object(pgs->memory, line, "fapi_image_uncached_glyph(line)");
1036
1037
6.76k
        code1 = gs_image_cleanup_and_free_enum(pie, penum_pgs);
1038
6.76k
        if (code >= 0 && code1 < 0)
1039
0
            code = code1;
1040
6.76k
    }
1041
10.5k
    return (code);
1042
10.5k
}
1043
1044
int
1045
gs_fapi_finish_render(gs_font *pfont, gs_gstate *pgs, gs_text_enum_t *penum, gs_fapi_server *I)
1046
1.07M
{
1047
1.07M
    gs_show_enum *penum_s = (gs_show_enum *) penum;
1048
1.07M
    gs_gstate *penum_pgs;
1049
1.07M
    gx_device *dev1;
1050
1.07M
    const int import_shift_v = _fixed_shift - 32;       /* we always 32.32 values for the outline interface now */
1051
1.07M
    gs_fapi_raster rast;
1052
1.07M
    int code;
1053
1.07M
    gs_memory_t *mem = pfont->memory;
1054
1.07M
    gs_font_base *pbfont = (gs_font_base *)pfont;
1055
1056
1.07M
    if (penum == NULL)
1057
0
        return_error(gs_error_undefined);
1058
1059
1.07M
    penum_pgs = penum_s->pgs;
1060
1061
1.07M
    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
1.07M
    if (pgs->in_charpath && !SHOW_IS(penum, TEXT_DO_NONE)) {
1068
2.03k
        gs_point pt;
1069
1070
2.03k
        if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1071
0
            return code;
1072
1073
2.03k
        if ((code =
1074
2.03k
             outline_char(mem, I, import_shift_v, penum_s, penum_pgs->path,
1075
2.03k
                          !pbfont->PaintType)) < 0) {
1076
0
            return code;
1077
0
        }
1078
1079
2.03k
        if ((code =
1080
2.03k
             gx_path_add_char_path(penum_pgs->show_gstate->path,
1081
2.03k
                                   penum_pgs->path,
1082
2.03k
                                   penum_pgs->in_charpath)) < 0) {
1083
0
            return code;
1084
0
        }
1085
1086
2.03k
    }
1087
1.07M
    else {
1088
1.07M
        int code;
1089
1.07M
        memset(&rast, 0x00, sizeof(rast));
1090
1091
1.07M
        if ((code = I->get_char_raster(I, &rast)) < 0 && code != gs_error_unregistered)
1092
0
            return code;
1093
1094
1.07M
        if (!SHOW_IS(penum, TEXT_DO_NONE) && I->use_outline) {
1095
            /* The server provides an outline instead the raster. */
1096
675k
            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
675k
            if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1105
14
                return code;
1106
1107
675k
            if ((code =
1108
675k
                 outline_char(mem, I, import_shift_v, penum_s,
1109
675k
                              penum_pgs->path, !pbfont->PaintType)) < 0)
1110
0
                return code;
1111
675k
            if ((code =
1112
675k
                 gs_gstate_setflat((gs_gstate *) penum_pgs,
1113
675k
                                   gs_char_flatness(penum_pgs->show_gstate, 1.0))) < 0)
1114
0
                return code;
1115
675k
            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
675k
            else {
1125
675k
                gs_in_cache_device_t in_cachedevice =
1126
675k
                    penum_pgs->in_cachedevice;
1127
1128
675k
                penum_pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1129
1130
675k
                penum_pgs->fill_adjust.x = penum_pgs->fill_adjust.y = 0;
1131
1132
675k
                code = gs_fill(penum_pgs);
1133
1134
675k
                penum_pgs->in_cachedevice = in_cachedevice;
1135
1136
675k
                if (code < 0)
1137
0
                    return code;
1138
675k
            }
1139
675k
            if ((code = gs_moveto(penum_pgs, pt.x, pt.y)) < 0)
1140
0
                return code;
1141
675k
        }
1142
399k
        else {
1143
399k
            int rast_orig_x = rast.orig_x;
1144
399k
            int rast_orig_y = -rast.orig_y;
1145
399k
            gs_point pt;
1146
1147
            /* This mimics code which is used above in the case where I->Use_outline is set.
1148
             * This is usually caused by setting -dTextAlphaBits, and will result in 'undefinedresult'
1149
             * errors. We want the code to work the same regardless off the setting of -dTextAlphaBits
1150
             * and it seems the simplest way to provoke the same error is to do the same steps....
1151
             * Note that we do not actually ever use the returned value.
1152
             */
1153
399k
            if ((code = gs_currentpoint(penum_pgs, &pt)) < 0)
1154
0
                return code;
1155
1156
399k
            if (penum_pgs->in_cachedevice == CACHE_DEVICE_CACHING) {    /* Using GS cache */
1157
                /*  GS and renderer may transform coordinates few differently.
1158
                   The best way is to make set_cache_device to take the renderer's bitmap metrics immediately,
1159
                   but we need to account CDevProc, which may truncate the bitmap.
1160
                   Perhaps GS overestimates the bitmap size,
1161
                   so now we only add a compensating shift - the dx and dy.
1162
                 */
1163
336k
                if (rast.width != 0) {
1164
336k
                    int shift_rd = _fixed_shift - frac_pixel_shift;
1165
336k
                    int rounding = 1 << (frac_pixel_shift - 1);
1166
336k
                    int dx =
1167
336k
                        arith_rshift_slow((penum_pgs->
1168
336k
                                           ctm.tx_fixed >> shift_rd) +
1169
336k
                                          rast_orig_x + rounding,
1170
336k
                                          frac_pixel_shift);
1171
336k
                    int dy =
1172
336k
                        arith_rshift_slow((penum_pgs->
1173
336k
                                           ctm.ty_fixed >> shift_rd) +
1174
336k
                                          rast_orig_y + rounding,
1175
336k
                                          frac_pixel_shift);
1176
1177
336k
                    if (dx + rast.left_indent < 0
1178
336k
                        || dx + rast.left_indent + rast.black_width >
1179
336k
                        dev1->width) {
1180
#ifdef DEBUG
1181
                        if (gs_debug_c('m')) {
1182
                            emprintf2(dev1->memory,
1183
                                      "Warning : Cropping a FAPI glyph while caching : dx=%d,%d.\n",
1184
                                      dx + rast.left_indent,
1185
                                      dx + rast.left_indent +
1186
                                      rast.black_width - dev1->width);
1187
                        }
1188
#endif
1189
0
                        if (dx + rast.left_indent < 0)
1190
0
                            dx -= dx + rast.left_indent;
1191
0
                    }
1192
336k
                    if (dy + rast.top_indent < 0
1193
336k
                        || dy + rast.top_indent + rast.black_height >
1194
336k
                        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
336k
                    if ((code = fapi_copy_mono(dev1, &rast, dx, dy)) < 0)
1208
0
                        return code;
1209
1210
336k
                    if (penum_s->cc != NULL) {
1211
336k
                        penum_s->cc->offset.x +=
1212
336k
                            float2fixed(penum_s->fapi_glyph_shift.x);
1213
336k
                        penum_s->cc->offset.y +=
1214
336k
                            float2fixed(penum_s->fapi_glyph_shift.y);
1215
336k
                    }
1216
336k
                }
1217
336k
            }
1218
63.2k
            else if (!SHOW_IS(penum, TEXT_DO_NONE)) {   /* Not using GS cache */
1219
10.5k
                if ((code =
1220
10.5k
                     fapi_image_uncached_glyph(pfont, pgs, penum_s, &rast,
1221
10.5k
                                               import_shift_v)) < 0)
1222
0
                    return code;
1223
10.5k
            }
1224
399k
        }
1225
1.07M
    }
1226
1227
1.07M
    return 0;
1228
1.07M
}
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
2.09M
#define MTX_EQ(mtx1,mtx2) (mtx1->xx == mtx2->xx && mtx1->xy == mtx2->xy && \
1235
1.01M
                           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
1.07M
{                               /* Stack : <font> <code|name> --> - */
1242
1.07M
    gs_show_enum *penum_s = (gs_show_enum *) penum;
1243
1.07M
    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
1.07M
    gs_fapi_char_ref cr =
1251
1.07M
        { 0, {0}, 0, false, NULL, 0, 0, 0, 0, 0, gs_fapi_metrics_notdef };
1252
1.07M
    gs_font_base *pbfont = (gs_font_base *)pfont;
1253
1.07M
    const gs_matrix *ctm = &ctm_only(pgs);
1254
1.07M
    int scale;
1255
1.07M
    gs_fapi_metrics metrics;
1256
1.07M
    gs_fapi_server *I = pbfont->FAPI;
1257
1258
1.07M
    gs_string enc_char_name_string;
1259
1.07M
    bool bCID = (FAPI_ISCIDFONT(pbfont) || charstring != NULL);
1260
1.07M
    bool bIsType1GlyphData = FAPI_ISTYPE1GLYPHDATA(pbfont);
1261
1.07M
    gs_log2_scale_point log2_scale = { 0, 0 };
1262
1.07M
    int alpha_bits = (*dev_proc(dev, get_alpha_bits)) (dev, go_text);
1263
1.07M
    double FontMatrix_div = 1;
1264
1.07M
    bool bVertical = (gs_rootfont(pgs)->WMode != 0), bVertical0 = bVertical;
1265
1.07M
    double *sbwp, sbw[4] = { 0, 0, 0, 0 };
1266
1.07M
    double em_scale_x, em_scale_y;
1267
1.07M
    gs_rect char_bbox;
1268
1.07M
    int code;
1269
1.07M
    bool imagenow = false;
1270
1.07M
    bool align_to_pixels = gs_currentaligntopixels(pbfont->dir);
1271
1.07M
    gs_memory_t *mem = pfont->memory;
1272
1.07M
    enum
1273
1.07M
    {
1274
1.07M
        SBW_DONE,
1275
1.07M
        SBW_SCALE,
1276
1.07M
        SBW_FROM_RENDERER
1277
1.07M
    } sbw_state = SBW_SCALE;
1278
1279
1.07M
    if ( index == GS_NO_GLYPH )
1280
91
        return 0;
1281
1282
1.07M
    I->use_outline = false;
1283
1.07M
    I->transform_outline = false;
1284
1285
1.07M
    if (penum == 0)
1286
0
        return_error(gs_error_undefined);
1287
1288
1.07M
    I->use_outline =
1289
1.07M
        produce_outline_char(penum_s, pbfont, alpha_bits, &log2_scale);
1290
1291
1.07M
    if (I->use_outline) {
1292
669k
        I->max_bitmap = 0;
1293
669k
    }
1294
407k
    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
407k
        I->max_bitmap =
1301
407k
            pbfont->dir->ccache.upper + (pbfont->dir->ccache.upper >> 1) <
1302
407k
            MAX_CCACHE_TEMP_BITMAP_BITS ? pbfont->dir->ccache.upper +
1303
407k
            (pbfont->dir->ccache.upper >> 1) : MAX_CCACHE_TEMP_BITMAP_BITS;
1304
407k
    }
1305
1306
1.07M
    if (pbfont->memory->gs_lib_ctx->font_dir != NULL)
1307
1.07M
        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
1.07M
    if (!SHOW_IS(penum, TEXT_DO_NONE) && !I->use_outline) {
1313
351k
        gs_currentcharmatrix(pgs, NULL, 1);     /* make char_tm valid */
1314
351k
        penum_s->fapi_log2_scale = log2_scale;
1315
351k
    }
1316
726k
    else {
1317
726k
        log2_scale.x = 0;
1318
726k
        log2_scale.y = 0;
1319
726k
    }
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
1.07M
    I->ff.memory = pbfont->memory;
1328
1.07M
    I->ff.subfont = subfont;
1329
1.07M
    I->ff.font_file_path = font_file_path;
1330
1.07M
    I->ff.client_font_data = pbfont;
1331
1.07M
    I->ff.client_font_data2 = pbfont;
1332
1.07M
    I->ff.server_font_data = pbfont->FAPI_font_data;
1333
1.07M
    I->ff.is_type1 = bIsType1GlyphData;
1334
1.07M
    I->ff.is_cid = bCID;
1335
1.07M
    I->ff.is_outline_font = pbfont->PaintType != 0;
1336
1.07M
    I->ff.metrics_only = fapi_gs_char_show_width_only(penum);
1337
1338
1.07M
    if (!I->ff.is_mtx_skipped)
1339
1.07M
        I->ff.is_mtx_skipped = (gs_fapi_get_metrics_count(&I->ff) != 0);
1340
1341
1.07M
    I->ff.is_vertical = bVertical;
1342
1.07M
    I->ff.client_ctx_p = I->client_ctx_p;
1343
1344
1.07M
    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
1.07M
   scale = 1 << I->frac_shift;
1355
1.08M
retry_oversampling:
1356
1.08M
    if (I->face.font_id != pbfont->id ||
1357
1.08M
        !MTX_EQ((&I->face.ctm), ctm) ||
1358
1.08M
        I->face.log2_scale.x != log2_scale.x ||
1359
1.08M
        I->face.log2_scale.y != log2_scale.y ||
1360
1.08M
        I->face.align_to_pixels != align_to_pixels ||
1361
1.08M
        I->face.HWResolution[0] != dev->HWResolution[0] ||
1362
1.08M
        I->face.HWResolution[1] != dev->HWResolution[1]
1363
1.08M
        ) {
1364
86.8k
        gs_fapi_font_scale font_scale = { {1, 0, 0, 1, 0, 0}
1365
86.8k
        , {0, 0}
1366
86.8k
        , {1, 1}
1367
86.8k
        , true
1368
86.8k
        };
1369
1370
86.8k
        gs_matrix lctm, scale_mat, scale_ctm;
1371
86.8k
        I->face.font_id = pbfont->id;
1372
86.8k
        I->face.log2_scale = log2_scale;
1373
86.8k
        I->face.align_to_pixels = align_to_pixels;
1374
86.8k
        I->face.HWResolution[0] = dev->HWResolution[0];
1375
86.8k
        I->face.HWResolution[1] = dev->HWResolution[1];
1376
1377
86.8k
        font_scale.subpixels[0] = 1 << log2_scale.x;
1378
86.8k
        font_scale.subpixels[1] = 1 << log2_scale.y;
1379
86.8k
        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
86.8k
        lctm = *ctm;
1385
91.2k
retry_scaling:
1386
91.2k
        I->face.ctm = lctm;
1387
91.2k
        memset(&scale_ctm, 0x00, sizeof(gs_matrix));
1388
91.2k
        scale_ctm.xx = dev->HWResolution[0] / 72;
1389
91.2k
        scale_ctm.yy = dev->HWResolution[1] / 72;
1390
1391
91.2k
        if ((code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm)) < 0)
1392
0
            return code;
1393
1394
91.2k
        if ((code = gs_matrix_multiply(&lctm, &scale_ctm, &scale_mat)) < 0)  /* scale_mat ==  CTM - resolution scaling */
1395
0
            return code;
1396
1397
91.2k
        if ((code = I->get_fontmatrix(I, &scale_ctm)) < 0)
1398
0
            return code;
1399
1400
91.2k
        if ((code = gs_matrix_invert((const gs_matrix *)&scale_ctm, &scale_ctm)) < 0)
1401
0
            return code;
1402
1403
91.2k
        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
91.2k
        if (((int64_t)(scale_mat.xx * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.xx * FontMatrix_div * scale + 0.5))
1407
91.2k
        ||  ((int64_t)(scale_mat.xy * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.xy * FontMatrix_div * scale + 0.5))
1408
91.2k
        ||  ((int64_t)(scale_mat.yx * FontMatrix_div * scale + 0.5)) != ((int32_t)(scale_mat.yx * FontMatrix_div * scale + 0.5))
1409
91.2k
        ||  ((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
4.35k
            memset(&lctm, 0x00, sizeof(gs_matrix));
1418
4.35k
            lctm.xx = 256.0;
1419
4.35k
            lctm.yy = 256.0;
1420
4.35k
            I->transform_outline = true;
1421
4.35k
            I->use_outline = true;
1422
4.35k
            if ((code = gs_matrix_invert((const gs_matrix *)&lctm, &scale_ctm)) < 0)
1423
0
                 return code;
1424
4.35k
            if ((code = gs_matrix_multiply(ctm, &scale_ctm, &scale_mat)) < 0)  /* scale_mat ==  CTM - resolution scaling */
1425
0
                return code;
1426
1427
4.35k
            I->outline_mat = scale_mat;
1428
4.35k
            goto retry_scaling;
1429
4.35k
        }
1430
86.8k
        else {
1431
86.8k
            font_scale.matrix[0] =  FAPI_ROUND_TO_FRACINT(scale_mat.xx * FontMatrix_div * scale);
1432
86.8k
            font_scale.matrix[1] = -FAPI_ROUND_TO_FRACINT(scale_mat.xy * FontMatrix_div * scale);
1433
86.8k
            font_scale.matrix[2] =  FAPI_ROUND_TO_FRACINT(scale_mat.yx * FontMatrix_div * scale);
1434
86.8k
            font_scale.matrix[3] = -FAPI_ROUND_TO_FRACINT(scale_mat.yy * FontMatrix_div * scale);
1435
86.8k
            font_scale.matrix[4] =  FAPI_ROUND_TO_FRACINT(scale_mat.tx * FontMatrix_div * scale);
1436
86.8k
            font_scale.matrix[5] =  FAPI_ROUND_TO_FRACINT(scale_mat.ty * FontMatrix_div * scale);
1437
86.8k
        }
1438
1439
        /* Note: the ctm mapping here is upside down. */
1440
86.8k
        font_scale.HWResolution[0] =
1441
86.8k
            (fracint) ((double)dev->HWResolution[0] *
1442
86.8k
                       font_scale.subpixels[0] * scale);
1443
86.8k
        font_scale.HWResolution[1] =
1444
86.8k
            (fracint) ((double)dev->HWResolution[1] *
1445
86.8k
                       font_scale.subpixels[1] * scale);
1446
1447
1448
86.8k
        if ((hypot((double)font_scale.matrix[0], (double)font_scale.matrix[2])
1449
86.8k
             == 0.0
1450
86.8k
             || hypot((double)font_scale.matrix[1],
1451
86.8k
                      (double)font_scale.matrix[3]) == 0.0)) {
1452
1453
            /* If the matrix is degenerate, force a scale to 1 unit. */
1454
3
            memset(&font_scale.matrix, 0x00, sizeof(font_scale.matrix));
1455
3
            if (!font_scale.matrix[0])
1456
3
                font_scale.matrix[0] = 1;
1457
3
            if (!font_scale.matrix[3])
1458
3
                font_scale.matrix[3] = 1;
1459
3
        }
1460
1461
86.8k
        if ((code =
1462
86.8k
             gs_fapi_renderer_retcode(mem, I,
1463
86.8k
                                      I->get_scaled_font(I, &I->ff,
1464
86.8k
                                                         &font_scale, NULL,
1465
86.8k
                                                         gs_fapi_toplevel_prepared))) < 0) {
1466
6
            return code;
1467
6
        }
1468
86.8k
        pbfont->FAPI_font_data = I->ff.server_font_data;    /* Save it back to GS font. */
1469
86.8k
    }
1470
1471
1.08M
    cr.char_codes_count = 1;
1472
1.08M
    cr.char_codes[0] = index;
1473
1.08M
    cr.client_char_code = chr;
1474
1.08M
    cr.is_glyph_index = true;
1475
1.08M
    enc_char_name_string.data = NULL;
1476
1.08M
    enc_char_name_string.size = 0;
1477
1478
1.08M
    if (I->ff.get_glyphname_or_cid) {
1479
1.08M
        if ((code =
1480
1.08M
             I->ff.get_glyphname_or_cid(penum, pbfont, charstring, glyphname, index,
1481
1.08M
                                        &enc_char_name_string, font_file_path,
1482
1.08M
                                        &cr, bCID)) < 0)
1483
0
            return (code);
1484
1.08M
    }
1485
1486
    /* Compute the metrics replacement : */
1487
1.08M
    if (bCID && !bIsType1GlyphData) {
1488
77.8k
        gs_font_cid2 *pfcid = (gs_font_cid2 *) pbfont;
1489
77.8k
        int MetricsCount = pfcid->cidata.MetricsCount;
1490
1491
77.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
77.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
1.08M
    em_scale_x = 1.0;
1519
1.08M
    if (pfont->FontType == ft_TrueType) {
1520
50.8k
        gs_font_type42 *pfont42 = (gs_font_type42 *) pfont;
1521
50.8k
        em_scale_x = pfont42->data.unitsPerEm;
1522
50.8k
    }
1523
1524
1.08M
    if (cr.metrics_type != gs_fapi_metrics_replace && bVertical) {
1525
419
        double pwv[4];
1526
1527
419
        code =
1528
419
            I->ff.fapi_get_metrics(&I->ff, &enc_char_name_string, index, pwv,
1529
419
                                   bVertical);
1530
419
        if (code < 0)
1531
0
            return code;
1532
419
        if (code == 0 /* metricsNone */ ) {
1533
419
            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
419
            else {
1546
419
                bVertical = false;
1547
419
            }
1548
419
        }
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
419
    }
1564
1.08M
    if (cr.metrics_type == gs_fapi_metrics_notdef && !bVertical) {
1565
1.08M
        code =
1566
1.08M
            I->ff.fapi_get_metrics(&I->ff, &enc_char_name_string, (int)index, sbw,
1567
1.08M
                                   bVertical);
1568
1.08M
        if (code < 0)
1569
0
            return code;
1570
1.08M
        if (code == 0 /* metricsNone */ ) {
1571
1.08M
            sbw_state = SBW_FROM_RENDERER;
1572
1.08M
            if (pbfont->FontType == 2) {
1573
33.6k
                gs_font_type1 *pfont1 = (gs_font_type1 *) pbfont;
1574
1575
33.6k
                cr.aw_x =
1576
33.6k
                    export_shift(pfont1->data.defaultWidthX,
1577
33.6k
                                 _fixed_shift - I->frac_shift);
1578
33.6k
                cr.metrics_scale = 1000;
1579
33.6k
                cr.metrics_type = gs_fapi_metrics_add;
1580
33.6k
            }
1581
1.08M
        }
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
1.08M
    }
1593
1.08M
    memset(&metrics, 0x00, sizeof(metrics));
1594
    /* Take metrics from font : */
1595
1.08M
    if (I->ff.metrics_only) {
1596
52.6k
        code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
1597
52.6k
    }
1598
1.02M
    else if (I->use_outline) {
1599
677k
        code = I->get_char_outline_metrics(I, &I->ff, &cr, &metrics);
1600
677k
    }
1601
350k
    else {
1602
350k
        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
350k
        if (code == gs_error_VMerror) {
1607
3.72k
            I->use_outline = true;
1608
3.72k
            goto retry_oversampling;
1609
3.72k
        }
1610
347k
        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
347k
    }
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
1.07M
    if (code > 0) {
1626
0
        return (gs_error_unregistered);
1627
0
    }
1628
1629
1.07M
    if ((code = gs_fapi_renderer_retcode(mem, I, code)) < 0)
1630
107
        return code;
1631
1632
1.07M
    compute_em_scale(pbfont, &metrics, FontMatrix_div, &em_scale_x,
1633
1.07M
                     &em_scale_y);
1634
1.07M
    char_bbox.p.x = metrics.bbox_x0 / em_scale_x;
1635
1.07M
    char_bbox.p.y = metrics.bbox_y0 / em_scale_y;
1636
1.07M
    char_bbox.q.x = metrics.bbox_x1 / em_scale_x;
1637
1.07M
    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
1.07M
    if (pbfont->FontType != ft_MicroType && !bCID
1643
1.07M
        && pbfont->FontBBox.q.x > pbfont->FontBBox.p.x
1644
1.07M
        && pbfont->FontBBox.q.y > pbfont->FontBBox.p.y) {
1645
993k
        char_bbox.p.x = min(char_bbox.p.x, pbfont->FontBBox.p.x);
1646
993k
        char_bbox.p.y = min(char_bbox.p.y, pbfont->FontBBox.p.y);
1647
993k
        char_bbox.q.x = max(char_bbox.q.x, pbfont->FontBBox.q.x);
1648
993k
        char_bbox.q.y = max(char_bbox.q.y, pbfont->FontBBox.q.y);
1649
993k
    }
1650
1651
1.07M
    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
1.07M
    penum_s->fapi_glyph_shift.x = penum_s->fapi_glyph_shift.y = 0;
1660
1.07M
    if (sbw_state == SBW_FROM_RENDERER) {
1661
1.07M
        int can_replace_metrics;
1662
1663
1.07M
        if ((code =
1664
1.07M
             gs_fapi_renderer_retcode(mem, I,
1665
1.07M
                                      I->can_replace_metrics(I, &I->ff, &cr,
1666
1.07M
                                                             &can_replace_metrics)))
1667
1.07M
            < 0)
1668
0
            return code;
1669
1670
1.07M
        sbw[2] = metrics.escapement / em_scale_x;
1671
1.07M
        sbw[3] = metrics.v_escapement / em_scale_y;
1672
1.07M
        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
1.07M
    }
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
1.07M
    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
1.07M
    if (I->ff.metrics_only) {
1744
52.6k
        pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1745
52.6k
    }
1746
1747
1.07M
    if (pgs->in_cachedevice == CACHE_DEVICE_CACHING) {
1748
0
        sbwp = sbw;
1749
0
    }
1750
1.07M
    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
1.07M
        sbwp = NULL;
1756
1757
1.07M
        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
677k
            pgs->in_cachedevice = CACHE_DEVICE_NOT_CACHING;
1763
677k
        }
1764
1.07M
    }
1765
1766
1.07M
    if (bCID) {
1767
77.6k
        code =
1768
77.6k
            I->ff.fapi_set_cache(penum, pbfont, &enc_char_name_string, index + GS_MIN_CID_GLYPH,
1769
77.6k
                                 sbw + 2, &char_bbox, sbwp, &imagenow);
1770
77.6k
    }
1771
999k
    else {
1772
999k
        code =
1773
999k
            I->ff.fapi_set_cache(penum, pbfont, &enc_char_name_string, index,
1774
999k
                                 sbw + 2, &char_bbox, sbwp, &imagenow);
1775
999k
    }
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
1.07M
    if (code >= 0 && imagenow == true) {
1784
1.07M
        code = gs_fapi_finish_render(pfont, pgs, penum, I);
1785
1.07M
        I->release_char_data(I);
1786
1.07M
    }
1787
1788
1.07M
    if (code != 0) {
1789
14
        if (code < 0) {
1790
            /* An error */
1791
14
            I->release_char_data(I);
1792
14
        }
1793
0
        else {
1794
            /* Callout to CDevProc, zsetcachedevice2, zfapi_finish_render. */
1795
0
        }
1796
14
    }
1797
1798
1.07M
    return code;
1799
1.07M
}
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
64.1k
{
1823
64.1k
    gs_font_base *pbfont;
1824
64.1k
    int code = 0;
1825
64.1k
    gs_fapi_server *I, **list;
1826
64.1k
    bool free_params = false;
1827
64.1k
    gs_memory_t *mem = pfont->memory;
1828
64.1k
    const char *ldecodingID = NULL;
1829
64.1k
    bool do_restart = false;
1830
1831
64.1k
    list = gs_fapi_get_server_list(mem);
1832
1833
64.1k
    if (!list) /* Should never happen */
1834
0
      return_error(gs_error_unregistered);
1835
1836
64.1k
    (*fapi_id) = NULL;
1837
1838
64.1k
    pbfont = (gs_font_base *) pfont;
1839
1840
64.1k
    I = *list;
1841
1842
64.1k
    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
64.3k
    while (I) {
1865
64.2k
        char *server_param = NULL;
1866
64.2k
        int server_param_size = 0;
1867
1868
64.2k
        code = (*get_server_param_cb) (I, (const char *)I->ig.d->subtype,
1869
64.2k
                                &server_param, &server_param_size);
1870
1871
64.2k
        if (code < 0)
1872
0
            return code;
1873
1874
64.2k
        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
64.2k
        if ((code =
1888
64.2k
             gs_fapi_renderer_retcode(mem, I,
1889
64.2k
                                      I->ensure_open(I, server_param,
1890
64.2k
                                                     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
64.2k
        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
64.2k
        pbfont->FAPI = I;       /* we need the FAPI server during this stage */
1902
64.2k
        code =
1903
64.2k
            gs_fapi_prepare_font(pfont, I, subfont, font_file_path,
1904
64.2k
                                 full_font_buf, xlatmap, &ldecodingID);
1905
64.2k
        if (code >= 0) {
1906
64.0k
            if (decodingID != NULL)
1907
63.7k
                *decodingID = (char *)ldecodingID;
1908
64.0k
            (*fapi_id) = (char *)I->ig.d->subtype;
1909
64.0k
            return 0;
1910
64.0k
        }
1911
1912
        /* renderer failed, continue search */
1913
138
        pbfont->FAPI = NULL;
1914
138
        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
138
        else {
1923
138
            I = *list;
1924
138
            list++;
1925
138
        }
1926
138
    }
1927
69
    return (code);
1928
64.1k
}
1929
1930
bool
1931
gs_fapi_available(gs_memory_t *mem, char *server)
1932
81.5k
{
1933
81.5k
    bool retval = false;
1934
1935
81.5k
    if (server) {
1936
8.88k
        gs_fapi_server *serv = NULL;
1937
1938
8.88k
        retval = (gs_fapi_find_server(mem, server, &serv, NULL) >= 0);
1939
8.88k
    }
1940
72.7k
    else {
1941
72.7k
        retval = ((mem->gs_lib_ctx->fapi_servers) != NULL) && (*(mem->gs_lib_ctx->fapi_servers) != NULL);
1942
72.7k
    }
1943
81.5k
    return (retval);
1944
81.5k
}
1945
1946
void
1947
gs_fapi_set_servers_client_data(gs_memory_t *mem, const gs_fapi_font *ff_proto, void *ctx_ptr)
1948
68.4k
{
1949
68.4k
    gs_fapi_server **servs = gs_fapi_get_server_list(mem);
1950
1951
68.4k
    if (servs) {
1952
136k
        while (*servs) {
1953
68.4k
            (*servs)->client_ctx_p = ctx_ptr;
1954
68.4k
            if (ff_proto)
1955
66.1k
                (*servs)->ff = *ff_proto;
1956
68.4k
            servs++;
1957
68.4k
        }
1958
68.4k
    }
1959
68.4k
}
1960
1961
gs_fapi_server **
1962
gs_fapi_get_server_list(gs_memory_t *mem)
1963
143k
{
1964
143k
    return (mem->gs_lib_ctx->fapi_servers);
1965
143k
}
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
10.8k
{
1971
10.8k
    gs_fapi_server **servs = gs_fapi_get_server_list(mem);
1972
10.8k
    char *server_param = NULL;
1973
10.8k
    int server_param_size = 0;
1974
10.8k
    int code = 0;
1975
10.8k
    bool free_params = false;
1976
1977
10.8k
    (*server) = NULL;
1978
1979
19.7k
    while (servs && *servs && strcmp((char *)(*servs)->ig.d->subtype, (char *)name)) {
1980
8.88k
        servs++;
1981
8.88k
    }
1982
1983
10.8k
    if (servs && *servs && get_server_param_cb) {
1984
1.96k
        code = (*get_server_param_cb) ((*servs), (char *) (*servs)->ig.d->subtype,
1985
1.96k
                                &server_param, &server_param_size);
1986
1987
1.96k
        if (code < 0)
1988
0
            return code;
1989
1990
1.96k
        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
1.96k
        code = gs_fapi_renderer_retcode(mem, (*servs),
2005
1.96k
                                 (*servs)->ensure_open((*servs),
2006
1.96k
                                                       server_param,
2007
1.96k
                                                       server_param_size));
2008
2009
1.96k
        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
1.96k
        (*server) = (*servs);
2015
1.96k
    }
2016
8.88k
    else {
2017
8.88k
        if (!servs || !(*servs)) {
2018
8.88k
            code = gs_error_invalidaccess;
2019
8.88k
        }
2020
8.88k
    }
2021
2022
2023
10.8k
    return (code);
2024
10.8k
}
2025
2026
int
2027
gs_fapi_init(gs_memory_t *mem)
2028
8.88k
{
2029
8.88k
    int code = 0;
2030
8.88k
    int i, num_servers = 0;
2031
8.88k
    gs_fapi_server **servs = NULL;
2032
8.88k
    const gs_fapi_server_init_func *gs_fapi_server_inits =
2033
8.88k
        gs_get_fapi_server_inits();
2034
2035
17.7k
    while (gs_fapi_server_inits[num_servers]) {
2036
8.88k
        num_servers++;
2037
8.88k
    }
2038
2039
8.88k
    servs =
2040
8.88k
        (gs_fapi_server **) gs_alloc_bytes_immovable(mem->non_gc_memory,
2041
8.88k
                                                     (num_servers +
2042
8.88k
                                                      1) *
2043
8.88k
                                                     sizeof(gs_fapi_server *),
2044
8.88k
                                                     "gs_fapi_init");
2045
8.88k
    if (!servs) {
2046
0
        return_error(gs_error_VMerror);
2047
0
    }
2048
2049
17.7k
    for (i = 0; i < num_servers; i++) {
2050
8.88k
        gs_fapi_server_init_func *f =
2051
8.88k
            (gs_fapi_server_init_func *) & (gs_fapi_server_inits[i]);
2052
2053
8.88k
        code = (*f) (mem, &(servs[i]));
2054
8.88k
        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
8.88k
        servs[i]->client_ctx_p = NULL;
2060
8.88k
    }
2061
2062
17.7k
    for (; i < num_servers + 1; i++) {
2063
8.88k
        servs[i] = NULL;
2064
8.88k
    }
2065
2066
8.88k
    mem->gs_lib_ctx->fapi_servers = servs;
2067
2068
8.88k
    return (code);
2069
8.88k
}
2070
2071
void
2072
gs_fapi_finit(gs_memory_t *mem)
2073
8.88k
{
2074
8.88k
    gs_fapi_server **servs = mem->gs_lib_ctx->fapi_servers;
2075
2076
17.7k
    while (servs && *servs) {
2077
8.88k
        ((*servs)->ig.d->finit) (servs);
2078
8.88k
        servs++;
2079
8.88k
    }
2080
8.88k
    gs_free_object(mem->non_gc_memory, mem->gs_lib_ctx->fapi_servers,
2081
8.88k
                   "gs_fapi_finit: mem->gs_lib_ctx->fapi_servers");
2082
8.88k
    mem->gs_lib_ctx->fapi_servers = NULL;
2083
8.88k
}