summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Deutschmann <whissi@gentoo.org>2019-10-15 12:24:12 +0200
committerThomas Deutschmann <whissi@gentoo.org>2020-08-13 11:26:55 +0200
commite088156d5b620e5e639580dacf85c6dc13823c74 (patch)
tree57f5c025e203279944da512166c20bc0521d8ccd /psi/zcharout.c
downloadghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.gz
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.tar.bz2
ghostscript-gpl-patches-e088156d5b620e5e639580dacf85c6dc13823c74.zip
Import Ghostscript 9.50ghostscript-9.50
Signed-off-by: Thomas Deutschmann <whissi@gentoo.org>
Diffstat (limited to 'psi/zcharout.c')
-rw-r--r--psi/zcharout.c423
1 files changed, 423 insertions, 0 deletions
diff --git a/psi/zcharout.c b/psi/zcharout.c
new file mode 100644
index 00000000..c1537281
--- /dev/null
+++ b/psi/zcharout.c
@@ -0,0 +1,423 @@
+/* Copyright (C) 2001-2019 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Common code for outline (Type 1 / 4 / 42) fonts */
+#include "memory_.h"
+#include "ghost.h"
+#include "oper.h"
+#include "gscrypt1.h"
+#include "gstext.h"
+#include "gxdevice.h" /* for gxfont.h */
+#include "gxfont.h"
+#include "gxfont1.h"
+#include "dstack.h" /* only for systemdict */
+#include "estack.h"
+#include "ichar.h"
+#include "icharout.h"
+#include "idict.h"
+#include "ifont.h"
+#include "igstate.h"
+#include "iname.h"
+#include "store.h"
+
+/*
+ * Execute an outline defined by a PostScript procedure.
+ * The top elements of the stack are:
+ * <font> <code|name> <name> <outline_id>
+ */
+int
+zchar_exec_char_proc(i_ctx_t *i_ctx_p)
+{
+ os_ptr op = osp;
+ /*
+ * The definition is a PostScript procedure. Execute
+ * <code|name> proc
+ * within a systemdict begin/end and a font begin/end.
+ */
+ es_ptr ep;
+
+ check_estack(5);
+ ep = esp += 5;
+ make_op_estack(ep - 4, zend);
+ make_op_estack(ep - 3, zend);
+ ref_assign(ep - 2, op);
+ make_op_estack(ep - 1, zbegin);
+ make_op_estack(ep, zbegin);
+ ref_assign(op - 1, systemdict);
+ {
+ ref rfont;
+
+ ref_assign(&rfont, op - 3);
+ ref_assign(op - 3, op - 2);
+ ref_assign(op - 2, &rfont);
+ }
+ pop(1);
+ return o_push_estack;
+}
+
+/*
+ * Get the metrics for a character from the Metrics dictionary of a base
+ * font. If present, store the l.s.b. in psbw[0,1] and the width in
+ * psbw[2,3].
+ */
+int /*metrics_present*/
+zchar_get_metrics(const gs_font_base * pbfont, const ref * pcnref,
+ double psbw[4])
+{
+ const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict;
+ ref *pmdict;
+
+ if (dict_find_string(pfdict, "Metrics", &pmdict) > 0) {
+ ref *pmvalue;
+
+ check_type_only(*pmdict, t_dictionary);
+ check_dict_read(*pmdict);
+ if (dict_find(pmdict, pcnref, &pmvalue) > 0) {
+ if (num_params(pmvalue, 1, psbw + 2) >= 0) { /* <wx> only */
+ psbw[3] = 0;
+ return metricsWidthOnly;
+ } else {
+ int code;
+
+ check_read_type_only(*pmvalue, t_array);
+ switch (r_size(pmvalue)) {
+ case 2: /* [<sbx> <wx>] */
+ code = num_params(pmvalue->value.refs + 1,
+ 2, psbw);
+ psbw[2] = psbw[1];
+ psbw[1] = psbw[3] = 0;
+ break;
+ case 4: /* [<sbx> <sby> <wx> <wy>] */
+ code = num_params(pmvalue->value.refs + 3,
+ 4, psbw);
+ break;
+ default:
+ return_error(gs_error_rangecheck);
+ }
+ if (code < 0)
+ return code;
+ return metricsSideBearingAndWidth;
+ }
+ }
+ }
+ return metricsNone;
+}
+
+/* Get the vertical metrics for a character from Metrics2, if present. */
+int
+zchar_get_metrics2(const gs_font_base * pbfont, const ref * pcnref,
+ double pwv[4])
+{
+ const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict;
+ ref *pmdict;
+
+ if (dict_find_string(pfdict, "Metrics2", &pmdict) > 0) {
+ ref *pmvalue;
+
+ check_type_only(*pmdict, t_dictionary);
+ check_dict_read(*pmdict);
+ if (dict_find(pmdict, pcnref, &pmvalue) > 0) {
+ check_read_type_only(*pmvalue, t_array);
+ if (r_size(pmvalue) == 4) {
+ int code = num_params(pmvalue->value.refs + 3, 4, pwv);
+
+ return (code < 0 ? code : metricsSideBearingAndWidth);
+ }
+ }
+ }
+ return metricsNone;
+}
+
+/*
+ * Get CDevProc.
+ */
+bool
+zchar_get_CDevProc(const gs_font_base * pbfont, ref **ppcdevproc)
+{
+ const ref *pfdict = &pfont_data(gs_font_parent(pbfont))->dict;
+
+ return dict_find_string(pfdict, "CDevProc", ppcdevproc) > 0;
+}
+
+/*
+ * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return
+ * o_push_estack if we had to call a CDevProc, or if we are skipping the
+ * rendering process (only getting the metrics).
+ * Returns exec_cont - a function, which must be called by caller after this function.
+ */
+int
+zchar_set_cache(i_ctx_t *i_ctx_p, const gs_font_base * pbfont,
+ const ref * pcnref, const double psb[2],
+ const double pwidth[2], const gs_rect * pbbox,
+ op_proc_t cont, op_proc_t *exec_cont,
+ const double Metrics2_sbw_default[4])
+{
+ os_ptr op = osp;
+ ref *pcdevproc, *valueref;
+ int have_cdevproc;
+ ref rpop;
+ ref cid, *cidptr;
+ bool metrics2;
+ bool metrics2_use_default = false;
+ double w2[10];
+ gs_text_enum_t *penum = op_show_find(i_ctx_p);
+
+ w2[0] = pwidth[0], w2[1] = pwidth[1];
+
+ /* Adjust the bounding box for stroking if needed. */
+
+ w2[2] = pbbox->p.x, w2[3] = pbbox->p.y;
+ w2[4] = pbbox->q.x, w2[5] = pbbox->q.y;
+ if (pbfont->PaintType != 0) {
+ double expand = max(1.415, gs_currentmiterlimit(igs)) *
+ gs_currentlinewidth(igs) / 2;
+
+ w2[2] -= expand, w2[3] -= expand;
+ w2[4] += expand, w2[5] += expand;
+ }
+
+ /* Check for Metrics2. */
+
+ {
+ int code = zchar_get_metrics2(pbfont, pcnref, w2 + 6);
+
+ if (code < 0)
+ return code;
+ metrics2 = code > 0;
+ }
+
+ /*
+ * For FontType 9 and 11, if Metrics2 is missing, the caller provides
+ * default Metrics2 values derived from the FontBBox.
+ */
+ if (!metrics2 && Metrics2_sbw_default != NULL) {
+ w2[6] = Metrics2_sbw_default[2];
+ w2[7] = Metrics2_sbw_default[3];
+ w2[8] = Metrics2_sbw_default[0];
+ w2[9] = Metrics2_sbw_default[1];
+ metrics2 = true;
+ metrics2_use_default = true;
+ }
+
+ /* Check for CDevProc or "short-circuiting". */
+
+ have_cdevproc = zchar_get_CDevProc(pbfont, &pcdevproc);
+
+ /* Obscure test. The CDevProc is supposed to be called with the original CID but what we get passed
+ * here is the TT GID. So the CDevProc won't do the right thing. We need to extract the CID from the
+ * enumerator, and use that instead.
+ */
+ cidptr = (ref *)pcnref;
+ if (pbfont->FontType == ft_CID_TrueType && dict_find_string(&pfont_data(gs_font_parent(pbfont))->dict, "File", &valueref) > 0) {
+ if (pbfont->key_name.size != pbfont->font_name.size ||
+ strncmp((const char *)pbfont->key_name.chars, (const char *)pbfont->font_name.chars, pbfont->key_name.size)) {
+
+ if (penum->returned.current_glyph >= GS_MIN_CID_GLYPH) {
+ make_int(&cid, penum->returned.current_glyph - GS_MIN_CID_GLYPH);
+ }
+ else {
+ make_int(&cid, penum->returned.current_glyph);
+ }
+ cidptr = &cid;
+ }
+ }
+ if (have_cdevproc || zchar_show_width_only(penum)) {
+ int i;
+ op_proc_t zsetc;
+ int nparams;
+
+ if (have_cdevproc) {
+ check_proc_only(*pcdevproc);
+ zsetc = zsetcachedevice2;
+
+ /* If we have cdevproc and the font type is CID type 0,
+ we'll throw away Metrics2_sbw_default that is calculated
+ from FontBBox. */
+ if (!metrics2
+ || (penum->current_font->FontType == ft_CID_encrypted
+ && metrics2_use_default)) {
+ w2[6] = w2[0], w2[7] = w2[1];
+ w2[8] = w2[9] = 0;
+ }
+ nparams = 10;
+ } else {
+ make_oper(&rpop, 0, zpop);
+ pcdevproc = &rpop;
+ if (metrics2)
+ zsetc = zsetcachedevice2, nparams = 10;
+ else
+ zsetc = zsetcachedevice, nparams = 6;
+ }
+ check_estack(3);
+ /* Push the l.s.b. for .type1addpath if necessary. */
+ if (psb != 0) {
+ push(nparams + 3);
+ make_real(op - (nparams + 2), psb[0]);
+ make_real(op - (nparams + 1), psb[1]);
+ } else {
+ push(nparams + 1);
+ }
+ for (i = 0; i < nparams; ++i)
+ make_real(op - nparams + i, w2[i]);
+ ref_assign(op, cidptr);
+ push_op_estack(cont);
+ push_op_estack(zsetc);
+ ++esp;
+ ref_assign(esp, pcdevproc);
+ return o_push_estack;
+ } {
+ int code =
+ (metrics2 ? gs_text_setcachedevice2(penum, w2) :
+ gs_text_setcachedevice(penum, w2));
+
+ if (code < 0)
+ return code;
+ }
+
+ /* No metrics modification, do the stroke or fill now. */
+
+ /* Push the l.s.b. for .type1addpath if necessary. */
+ if (psb != 0) {
+ push(2);
+ make_real(op - 1, psb[0]);
+ make_real(op, psb[1]);
+ }
+ *exec_cont = cont;
+ return 0;
+}
+
+/*
+ * Get the CharString data corresponding to a glyph. Return typecheck
+ * if it isn't a string.
+ */
+static bool charstring_is_notdef_proc(const gs_memory_t *mem, const ref *);
+static int charstring_make_notdef(gs_glyph_data_t *, gs_font *);
+int
+zchar_charstring_data(gs_font *font, const ref *pgref, gs_glyph_data_t *pgd)
+{
+ ref *pcstr;
+
+ if (dict_find(&pfont_data(font)->CharStrings, pgref, &pcstr) <= 0)
+ return_error(gs_error_undefined);
+ if (!r_has_type(pcstr, t_string)) {
+ /*
+ * The ADOBEPS4 Windows driver replaces the .notdef entry of
+ * otherwise normal Type 1 fonts with the procedure
+ * {pop 0 0 setcharwidth}
+ * To prevent this from making the font unembeddable in PDF files
+ * (with our present font-writing code), we recognize this as a
+ * special case and return a Type 1 CharString consisting of
+ * 0 0 hsbw endchar
+ */
+ if (font->FontType == ft_encrypted &&
+ charstring_is_notdef_proc(font->memory, pcstr)
+ )
+ return charstring_make_notdef(pgd, font);
+ else
+ return_error(gs_error_typecheck);
+ }
+ gs_glyph_data_from_string(pgd, pcstr->value.const_bytes, r_size(pcstr),
+ NULL);
+ return 0;
+}
+static bool
+charstring_is_notdef_proc(const gs_memory_t *mem, const ref *pcstr)
+{
+ if (r_is_array(pcstr) && r_size(pcstr) == 4) {
+ ref elts[4];
+ long i;
+
+ for (i = 0; i < 4; ++i)
+ array_get(mem, pcstr, i, &elts[i]);
+ if (r_has_type(&elts[0], t_name) &&
+ r_has_type(&elts[1], t_integer) && elts[1].value.intval == 0 &&
+ r_has_type(&elts[2], t_integer) && elts[2].value.intval == 0 &&
+ r_has_type(&elts[3], t_name)
+ ) {
+ ref nref;
+
+ name_enter_string(mem, "pop", &nref);
+ if (name_eq(&elts[0], &nref)) {
+ name_enter_string(mem, "setcharwidth", &nref);
+ if (name_eq(&elts[3], &nref))
+ return true;
+ }
+ }
+ }
+ return false;
+}
+static int
+charstring_make_notdef(gs_glyph_data_t *pgd, gs_font *font)
+{
+ gs_font_type1 *const pfont = (gs_font_type1 *)font;
+ static const byte char_data[4] = {
+ 139, /* 0 */
+ 139, /* 0 */
+ c1_hsbw,
+ cx_endchar
+ };
+ uint len = max(pfont->data.lenIV, 0) + sizeof(char_data);
+ byte *chars = gs_alloc_string(font->memory, len, "charstring_make_notdef");
+
+ if (chars == 0)
+ return_error(gs_error_VMerror);
+ gs_glyph_data_from_string(pgd, chars, len, font);
+ if (pfont->data.lenIV < 0)
+ memcpy(chars, char_data, sizeof(char_data));
+ else {
+ crypt_state state = crypt_charstring_seed;
+
+ memcpy(chars + pfont->data.lenIV, char_data, sizeof(char_data));
+ gs_type1_encrypt(chars, chars, len, &state);
+ }
+ return 0;
+}
+
+/*
+ * Enumerate the next glyph from a directory. This is essentially a
+ * wrapper around dict_first/dict_next to implement the enumerate_glyph
+ * font procedure.
+ *
+ * Note that *prdict will be null if the font is a subfont of a
+ * CIDFontType 0 CIDFont.
+ */
+int
+zchar_enumerate_glyph(const gs_memory_t *mem, const ref *prdict, int *pindex, gs_glyph *pglyph)
+{
+ int index = *pindex - 1;
+ ref elt[2];
+
+ if (!r_has_type(prdict, t_dictionary))
+ return 0; /* *pindex was 0, is still 0 */
+ if (index < 0)
+ index = dict_first(prdict);
+next:
+ index = dict_next(prdict, index, elt);
+ *pindex = index + 1;
+ if (index >= 0) {
+ switch (r_type(elt)) {
+ case t_integer:
+ *pglyph = GS_MIN_CID_GLYPH + elt[0].value.intval;
+ break;
+ case t_name:
+ *pglyph = name_index(mem, elt);
+ break;
+ default: /* can't handle it */
+ goto next;
+ }
+ }
+ return 0;
+}