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