Coverage Report

Created: 2025-11-16 07:40

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