/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 | | }; |