Coverage Report

Created: 2026-02-14 07:09

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