Coverage Report

Created: 2025-06-10 07:26

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