Coverage Report

Created: 2022-10-31 07:00

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