1 /* Copyright (C) 2001-2012 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., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, 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 "gxistate.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
zchar42_set_cache(i_ctx_t * i_ctx_p,gs_font_base * pbfont,ref * cnref,uint glyph_index,op_proc_t cont,op_proc_t * exec_cont)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 { double sbw[4];
47 double w[2];
48 int present;
49 gs_font_type42 *pfont42 = (gs_font_type42 *)pbfont;
50 int code = zchar_get_metrics(pbfont, cnref, sbw);
51 gs_rect bbox;
52 int vertical = gs_rootfont(igs)->WMode;
53 float sbw_bbox[8];
54 float sbw_bbox_h[8];
55 ref *fdict = (ref *)pbfont->client_data;
56 ref *rpath = NULL;
57 bool embedded = true;
58
59 if (code < 0)
60 return code;
61 present = code;
62
63 if (dict_find_string(fdict, "Path", &rpath) > 0) {
64 embedded = false;
65 }
66
67 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 code = pfont42->data.get_metrics(pfont42, glyph_index,
72 gs_type42_metrics_options_WMODE0_AND_BBOX, sbw_bbox_h);
73 if (code < 0)
74 return code;
75 code = pfont42->data.get_metrics(pfont42, glyph_index,
76 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 if (code < 0 && !embedded) {
85 /* No vertical metrics in the font,
86 hewristically compose vertical metrics from bounding boxes. */
87 sbw_bbox[0] = 0;
88 sbw_bbox[1] = pbfont->FontBBox.q.y - 1;
89 sbw_bbox[2] = 0;
90 sbw_bbox[3] = -1;
91 }
92 else {
93 vertical = false;
94 }
95 }
96 if (vertical) {
97 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 sbw[0] = sbw_bbox_h[2] / 2;
110 sbw[1] = sbw_bbox[1] - sbw_bbox[3];
111 # endif
112 }
113 if (present == metricsNone) {
114 /* No adwance width (in Metrcis2) in Postscript font. */
115 sbw[2] = 0;
116 sbw[3] = sbw_bbox[3];
117 }
118 } 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 code = pfont42->data.get_metrics(pfont42, glyph_index,
122 gs_type42_metrics_options_WMODE0_AND_BBOX, sbw_bbox);
123 if (code < 0)
124 return code;
125 if (present != metricsSideBearingAndWidth) {
126 /* metricsNone or metricsWidthOnly. */
127 /* No left side bearing (in Metrics) in Postscript font. */
128 sbw[0] = sbw_bbox[0];
129 sbw[1] = sbw_bbox[1];
130 }
131 if (present == metricsNone) {
132 /* No advance width (in Metrics) in Postscript font. */
133 sbw[2] = sbw_bbox[2];
134 sbw[3] = sbw_bbox[3];
135 }
136 }
137 w[0] = sbw[2];
138 w[1] = sbw[3];
139 if (!vertical) {
140 sbw_bbox[6] = (sbw_bbox[6] - sbw_bbox[4]) + sbw_bbox[0];
141 sbw_bbox[4] = sbw_bbox[0];
142 }
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 bbox.p.x = min(sbw_bbox[4], pbfont->FontBBox.p.y);
148 bbox.p.y = min(sbw_bbox[5], pbfont->FontBBox.p.y);
149 bbox.q.x = max(sbw_bbox[6], pbfont->FontBBox.q.x);
150 bbox.q.y = max(sbw_bbox[7], pbfont->FontBBox.q.y);
151 return zchar_set_cache(i_ctx_p, pbfont, cnref,
152 NULL,
153 w, &bbox,
154 cont, exec_cont,
155 vertical ? sbw : NULL);
156 }
157
158 /* <font> <code|name> <name> <glyph_index> .type42execchar - */
159 static int type42_fill(i_ctx_t *);
160 static int type42_stroke(i_ctx_t *);
161 static int
ztype42execchar(i_ctx_t * i_ctx_p)162 ztype42execchar(i_ctx_t *i_ctx_p)
163 {
164 os_ptr op = osp;
165 gs_font *pfont;
166 int code = font_param(op - 3, &pfont);
167 gs_font_base *const pbfont = (gs_font_base *) pfont;
168 gs_font_type42 *const pfont42 = (gs_font_type42 *) pfont;
169 gs_text_enum_t *penum = op_show_find(i_ctx_p);
170 op_proc_t cont = (pbfont->PaintType == 0 ? type42_fill : type42_stroke), exec_cont = 0;
171 ref *cnref;
172 uint glyph_index;
173
174 if (code < 0)
175 return code;
176 if (penum == 0 ||
177 (pfont->FontType != ft_TrueType &&
178 pfont->FontType != ft_CID_TrueType)
179 )
180 return_error(e_undefined);
181 /*
182 * Any reasonable implementation would execute something like
183 * 1 setmiterlimit 0 setlinejoin 0 setlinecap
184 * here, but apparently the Adobe implementations aren't reasonable.
185 *
186 * If this is a stroked font, set the stroke width.
187 */
188 if (pfont->PaintType)
189 gs_setlinewidth(igs, pfont->StrokeWidth);
190 check_estack(3); /* for continuations */
191 /*
192 * Execute the definition of the character.
193 */
194 if (r_is_proc(op))
195 return zchar_exec_char_proc(i_ctx_p);
196 /*
197 * The definition must be a Type 42 glyph index.
198 * Note that we do not require read access: this is deliberate.
199 */
200 check_type(*op, t_integer);
201 check_ostack(3); /* for lsb values */
202 /* Establish a current point. */
203 code = gs_moveto(igs, 0.0, 0.0);
204 if (code < 0)
205 return code;
206 cnref = op - 1;
207 glyph_index = (uint)op->value.intval;
208 if (pfont42->data.gsub_size) {
209 glyph_index = pfont42->data.substitute_glyph_index_vertical(pfont42, glyph_index,
210 gs_rootfont(igs)->WMode, penum->returned.current_glyph);
211 make_int(op, glyph_index);
212 }
213 code = zchar42_set_cache(i_ctx_p, pbfont, cnref, glyph_index, cont, &exec_cont);
214 if (code >= 0 && exec_cont != 0)
215 code = (*exec_cont)(i_ctx_p);
216 return code;
217 }
218
219 /* Continue after a CDevProc callout. */
220 static int type42_finish(i_ctx_t *i_ctx_p,
221 int (*cont)(gs_state *));
222 static int
type42_fill(i_ctx_t * i_ctx_p)223 type42_fill(i_ctx_t *i_ctx_p)
224 {
225 int code;
226 gs_fixed_point fa = i_ctx_p->pgs->fill_adjust;
227
228 i_ctx_p->pgs->fill_adjust.x = i_ctx_p->pgs->fill_adjust.y = -1;
229 code = type42_finish(i_ctx_p, gs_fill);
230 i_ctx_p->pgs->fill_adjust = fa; /* Not sure whether we need to restore it,
231 but this isn't harmful. */
232 return code;
233 }
234 static int
type42_stroke(i_ctx_t * i_ctx_p)235 type42_stroke(i_ctx_t *i_ctx_p)
236 {
237 return type42_finish(i_ctx_p, gs_stroke);
238 }
239 /* <font> <code|name> <name> <glyph_index> %type42_{fill|stroke} - */
240 static int
type42_finish(i_ctx_t * i_ctx_p,int (* cont)(gs_state *))241 type42_finish(i_ctx_t *i_ctx_p, int (*cont) (gs_state *))
242 {
243 os_ptr op = osp;
244 gs_font *pfont;
245 gs_font_type42 *pfont42;
246 int code;
247 gs_text_enum_t *penum = op_show_find(i_ctx_p);
248 os_ptr opc = op;
249 uint glyph_index;
250
251 check_type(*opc, t_integer);
252 code = font_param(opc - 3, &pfont);
253 if (code < 0)
254 return code;
255 if (penum == 0 || (pfont->FontType != ft_TrueType &&
256 pfont->FontType != ft_CID_TrueType)
257 )
258 return_error(e_undefined);
259 pfont42 = (gs_font_type42 *)pfont;
260
261 if (!i_ctx_p->RenderTTNotdef) {
262 if (r_has_type(opc - 1, t_name)) {
263 ref gref;
264
265 name_string_ref(imemory, opc - 1, &gref);
266 if ((gref.tas.rsize == 7 && strncmp((const char *)gref.value.const_bytes, ".notdef", 7) == 0) ||
267 (gref.tas.rsize > 9 && strncmp((const char *)gref.value.const_bytes, ".notdef~GS", 10) == 0)) {
268 pop(4);
269 return (*cont)(igs);
270 }
271 }
272 }
273 glyph_index = (uint)opc->value.intval;
274 if (pfont42->data.gsub_size)
275 glyph_index = pfont42->data.substitute_glyph_index_vertical(pfont42, glyph_index,
276 gs_rootfont(igs)->WMode, penum->returned.current_glyph);
277 /*
278 * We have to disregard penum->pis and penum->path, and render to
279 * the current gstate and path. This is a design bug that we will
280 * have to address someday!
281 */
282 code = gs_type42_append(glyph_index, igs,
283 igs->path, penum, pfont,
284 (penum->text.operation & TEXT_DO_ANY_CHARPATH) != 0);
285 if (code < 0)
286 return code;
287 pop(4);
288 return (*cont)(igs);
289 }
290
291 /* ------ Initialization procedure ------ */
292
293 const op_def zchar42_op_defs[] =
294 {
295 {"4.type42execchar", ztype42execchar},
296 op_def_end(0)
297 };
298