Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/zchar42.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* Type 42 character display operator */
18
#include "ghost.h"
19
#include "oper.h"
20
#include "gsmatrix.h"
21
#include "gspaint.h"    /* for gs_fill, gs_stroke */
22
#include "gspath.h"
23
#include "gxfixed.h"
24
#include "gxfont.h"
25
#include "gxfont42.h"
26
#include "gxgstate.h"
27
#include "gxpath.h"
28
#include "gxtext.h"
29
#include "gzstate.h"    /* only for ->path */
30
#include "dstack.h"   /* only for systemdict */
31
#include "estack.h"
32
#include "ichar.h"
33
#include "icharout.h"
34
#include "ifont.h"    /* for font_param */
35
#include "igstate.h"
36
#include "iname.h"
37
#include "store.h"
38
#include "string_.h"
39
#include "zchar42.h"
40
#include "idict.h"
41
42
/* Get a Type 42 character metrics and set the cache device. */
43
int
44
zchar42_set_cache(i_ctx_t *i_ctx_p, gs_font_base *pbfont, ref *cnref,
45
            uint glyph_index, op_proc_t cont, op_proc_t *exec_cont)
46
0
{   double sbw[4];
47
0
    double w[2];
48
0
    int present;
49
0
    gs_font_type42 *pfont42 = (gs_font_type42 *)pbfont;
50
0
    int code = zchar_get_metrics(pbfont, cnref, sbw);
51
0
    gs_rect bbox;
52
0
    int vertical = gs_rootfont(igs)->WMode;
53
0
    float sbw_bbox[8];
54
0
    float sbw_bbox_h[8];
55
0
    ref *fdict = (ref *)pbfont->client_data;
56
0
    ref *rpath = NULL;
57
0
    bool embedded = true;
58
59
0
    if (code < 0)
60
0
        return code;
61
0
    present = code;
62
63
0
    if (dict_find_string(fdict, "Path", &rpath) > 0) {
64
0
        embedded = false;
65
0
    }
66
67
0
    if (vertical) { /* for vertically-oriented metrics */
68
69
        /* Always call get_metrics because we'll need glyph bbox below in any case
70
           as a workaround for Dynalab fonts. We can't recognize Dynalab here. */
71
0
        code = pfont42->data.get_metrics(pfont42, glyph_index,
72
0
                    gs_type42_metrics_options_WMODE0_AND_BBOX, sbw_bbox_h);
73
0
        if (code < 0)
74
0
            return code;
75
0
        code = pfont42->data.get_metrics(pfont42, glyph_index,
76
0
                gs_type42_metrics_options_WMODE1_AND_BBOX, sbw_bbox);
77
        /* Here code=0 means success, code<0 means no vertical metrics. */
78
        /* We only want to create fake vertical metrics for TTF fonts
79
           being used to emulate a vertical writing CIDFont. If we have
80
           a CIDType 2 font, without vertical metrics, we're supposed to
81
           treat it as a horizontal writing font, regardless of the wmode
82
           setting
83
         */
84
0
        if (code < 0 && !embedded) {
85
            /* No vertical metrics in the font,
86
               hewristically compose vertical metrics from bounding boxes. */
87
0
            sbw_bbox[0] = 0;
88
0
            sbw_bbox[1] = pbfont->FontBBox.q.y - 1;
89
0
            sbw_bbox[2] = 0;
90
0
            sbw_bbox[3] = -1;
91
0
        }
92
0
        else {
93
0
            vertical = false;
94
0
        }
95
0
    }
96
0
    if (vertical) {
97
0
        if (present != metricsSideBearingAndWidth) {
98
            /* metricsNone or metricsWidthOnly. */
99
            /* No top side bearing (in Metrics2) in Postscript font. */
100
            /* Note that Postscript wants the 'V' vector in sbw[0:1],
101
               and True Type supplies Top Side Bearing in sbw_bbox[0:1],
102
               and Left Side Bearing in sbw_bbox_h[0:1].
103
               So we need to compute V from FontBBox as we do for FontType 9
104
               (see FontBBox_as_Metrics2) and add TSB to it. */
105
#     if 0 /* old code taken from empirics, keepping it for a while to compare results. */
106
            sbw[0] = (sbw_bbox[6] + sbw_bbox[4]) / 2;
107
            sbw[1] = (pbfont->FontBBox.q.y + pbfont->FontBBox.p.y - sbw_bbox[3]) / 2;
108
#     else
109
0
            sbw[0] = sbw_bbox_h[2] / 2;
110
0
            sbw[1] = sbw_bbox[1] - sbw_bbox[3];
111
0
#     endif
112
0
        }
113
0
        if (present == metricsNone) {
114
            /* No adwance width (in Metrcis2) in Postscript font. */
115
0
            sbw[2] = 0;
116
0
            sbw[3] = sbw_bbox[3];
117
0
        }
118
0
    } else {
119
        /* Always call get_metrics because we'll need glyph bbox below in any case
120
           as a workaround for Dynalab fonts. We can't recognize Dynalab here. */
121
0
        code = pfont42->data.get_metrics(pfont42, glyph_index,
122
0
                    gs_type42_metrics_options_WMODE0_AND_BBOX, sbw_bbox);
123
0
        if (code < 0)
124
0
            return code;
125
0
        if (present != metricsSideBearingAndWidth) {
126
            /* metricsNone or metricsWidthOnly. */
127
            /* No left side bearing (in Metrics) in Postscript font. */
128
0
            sbw[0] = sbw_bbox[0];
129
0
            sbw[1] = sbw_bbox[1];
130
0
        }
131
0
        if (present == metricsNone) {
132
            /* No advance width (in Metrics) in Postscript font. */
133
0
            sbw[2] = sbw_bbox[2];
134
0
            sbw[3] = sbw_bbox[3];
135
0
        }
136
0
    }
137
0
    w[0] = sbw[2];
138
0
    w[1] = sbw[3];
139
0
    if (!vertical) {
140
0
        sbw_bbox[6] = (sbw_bbox[6] - sbw_bbox[4]) + sbw_bbox[0];
141
0
        sbw_bbox[4] = sbw_bbox[0];
142
0
    }
143
    /* Note: The glyph bbox usn't useful for Dynalab fonts,
144
       which stretch subglyphs. Uniting with FontBBox helps.
145
       In same time, FontBBox with no glyph bbox
146
       doesn't work for 34_all.PS page 4. */
147
    /* Previously we used to expand the bbox to the maximum/minimum
148
     * of the glyph and font bounding boxes combined, as noted above.
149
     * However this causes incorrect output (bug #703697) for vertical
150
     * writing fonts with pdfwrite. Since we no longer use this code
151
     * for rendering, and pdfwrite doesn't use the metrics for clipping,
152
     * but does for positioning, we've removed this code.
153
     */
154
155
0
    bbox.p.x = sbw_bbox[4];
156
0
    bbox.p.y = sbw_bbox[5];
157
0
    bbox.q.x = sbw_bbox[6];
158
0
    bbox.q.y = sbw_bbox[7];
159
0
    return zchar_set_cache(i_ctx_p, pbfont, cnref,
160
0
                           NULL,
161
0
                           w, &bbox,
162
0
                           cont, exec_cont,
163
0
                           vertical ? sbw : NULL);
164
0
}
165
166
/* <font> <code|name> <name> <glyph_index> .type42execchar - */
167
static int type42_fill(i_ctx_t *);
168
static int type42_stroke(i_ctx_t *);
169
static int
170
ztype42execchar(i_ctx_t *i_ctx_p)
171
0
{
172
0
    os_ptr op = osp;
173
0
    gs_font *pfont;
174
0
    int code;
175
0
    gs_font_base *pbfont;
176
0
    gs_font_type42 *pfont42;
177
0
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
178
0
    op_proc_t cont, exec_cont = 0;
179
0
    ref *cnref;
180
0
    uint glyph_index;
181
182
0
    check_op(4);
183
0
    check_type(*(op - 1), t_name);
184
0
    if (!r_has_type((op - 2), t_name)) {
185
0
        check_type(*(op - 2), t_integer);
186
0
    }
187
188
0
    code = font_param(op - 3, &pfont);
189
0
    if (code < 0)
190
0
        return code;
191
192
0
    pbfont = (gs_font_base *) pfont;
193
0
    cont = (pbfont->PaintType == 0 ? type42_fill : type42_stroke);
194
0
    pfont42 = (gs_font_type42 *) pfont;
195
196
0
    if (penum == 0 ||
197
0
        (pfont->FontType != ft_TrueType &&
198
0
         pfont->FontType != ft_CID_TrueType)
199
0
        )
200
0
        return_error(gs_error_undefined);
201
    /*
202
     * Any reasonable implementation would execute something like
203
     *  1 setmiterlimit 0 setlinejoin 0 setlinecap
204
     * here, but apparently the Adobe implementations aren't reasonable.
205
     *
206
     * If this is a stroked font, set the stroke width.
207
     */
208
0
    if (pfont->PaintType)
209
0
        gs_setlinewidth(igs, pfont->StrokeWidth);
210
0
    check_estack(3);   /* for continuations */
211
    /*
212
     * Execute the definition of the character.
213
     */
214
0
    if (r_is_proc(op))
215
0
        return zchar_exec_char_proc(i_ctx_p);
216
    /*
217
     * The definition must be a Type 42 glyph index.
218
     * Note that we do not require read access: this is deliberate.
219
     */
220
0
    check_type(*op, t_integer);
221
0
    check_ostack(3);   /* for lsb values */
222
    /* Establish a current point. */
223
0
    code = gs_moveto(igs, 0.0, 0.0);
224
0
    if (code < 0)
225
0
        return code;
226
0
    cnref = op - 1;
227
0
    glyph_index = (uint)op->value.intval;
228
0
    if (pfont42->data.gsub_size) {
229
0
        glyph_index = pfont42->data.substitute_glyph_index_vertical(pfont42, glyph_index,
230
0
                gs_rootfont(igs)->WMode, penum->returned.current_glyph);
231
0
        make_int(op, glyph_index);
232
0
    }
233
0
    code = zchar42_set_cache(i_ctx_p, pbfont, cnref, glyph_index, cont, &exec_cont);
234
0
    if (code >= 0 && exec_cont != 0)
235
0
        code = (*exec_cont)(i_ctx_p);
236
0
    return code;
237
0
}
238
239
/* Continue after a CDevProc callout. */
240
static int type42_finish(i_ctx_t *i_ctx_p,
241
                          int (*cont)(gs_gstate *));
242
static int
243
type42_fill(i_ctx_t *i_ctx_p)
244
0
{
245
0
    int code;
246
0
    gs_fixed_point fa = i_ctx_p->pgs->fill_adjust;
247
248
0
    i_ctx_p->pgs->fill_adjust.x = i_ctx_p->pgs->fill_adjust.y = -1;
249
0
    code = type42_finish(i_ctx_p, gs_fill);
250
0
    i_ctx_p->pgs->fill_adjust = fa; /* Not sure whether we need to restore it,
251
                                       but this isn't harmful. */
252
0
    return code;
253
0
}
254
static int
255
type42_stroke(i_ctx_t *i_ctx_p)
256
0
{
257
0
    return type42_finish(i_ctx_p, gs_stroke);
258
0
}
259
/* <font> <code|name> <name> <glyph_index> %type42_{fill|stroke} - */
260
static int
261
type42_finish(i_ctx_t *i_ctx_p, int (*cont) (gs_gstate *))
262
0
{
263
0
    os_ptr op = osp;
264
0
    gs_font *pfont;
265
0
    gs_font_type42 *pfont42;
266
0
    int code;
267
0
    gs_text_enum_t *penum = op_show_find(i_ctx_p);
268
0
    os_ptr opc = op;
269
0
    uint glyph_index;
270
271
0
    check_type(*opc, t_integer);
272
0
    code = font_param(opc - 3, &pfont);
273
0
    if (code < 0)
274
0
        return code;
275
0
    if (penum == 0 || (pfont->FontType != ft_TrueType &&
276
0
                       pfont->FontType != ft_CID_TrueType)
277
0
        )
278
0
        return_error(gs_error_undefined);
279
0
    pfont42 = (gs_font_type42 *)pfont;
280
281
0
    if (!i_ctx_p->RenderTTNotdef) {
282
0
        if (r_has_type(opc - 1, t_name)) {
283
0
            ref gref;
284
285
0
            name_string_ref(imemory, opc - 1, &gref);
286
0
            if ((gref.tas.rsize == 7 && strncmp((const char *)gref.value.const_bytes, ".notdef", 7) == 0) ||
287
0
                (gref.tas.rsize > 9 && strncmp((const char *)gref.value.const_bytes, ".notdef~GS", 10) == 0)) {
288
0
                pop(4);
289
0
                return (*cont)(igs);
290
0
            }
291
0
        }
292
0
    }
293
0
    glyph_index = (uint)opc->value.intval;
294
0
    if (pfont42->data.gsub_size)
295
0
        glyph_index = pfont42->data.substitute_glyph_index_vertical(pfont42, glyph_index,
296
0
                    gs_rootfont(igs)->WMode, penum->returned.current_glyph);
297
    /*
298
     * We have to disregard penum->pis and penum->path, and render to
299
     * the current gstate and path.  This is a design bug that we will
300
     * have to address someday!
301
     */
302
0
    code = gs_type42_append(glyph_index, igs,
303
0
                            igs->path, penum, pfont,
304
0
                            (penum->text.operation & TEXT_DO_ANY_CHARPATH) != 0);
305
0
    if (code < 0)
306
0
        return code;
307
0
    pop(4);
308
0
    return (*cont)(igs);
309
0
}
310
311
/* ------ Initialization procedure ------ */
312
313
const op_def zchar42_op_defs[] =
314
{
315
    {"4.type42execchar", ztype42execchar},
316
    op_def_end(0)
317
};