/* the code for Type 1 halftones in sethalftone. */ int zscreen_enum_init(i_ctx_t *i_ctx_p, const gx_ht_order * porder, gs_screen_halftone * psp, ref * pproc, int npop, int (*finish_proc)(i_ctx_t *), int space_index) { gs_screen_enum *penum; gs_memory_t * mem = (gs_memory_t *)idmemory->spaces_indexed[space_index]; int code; check_estack(snumpush + 1); penum = gs_screen_enum_alloc(mem, "setscreen"); if (penum == 0) return_error(e_VMerror); make_struct(esp + snumpush, space_index << r_space_shift, penum); /* do early for screen_cleanup in case of error */ code = gs_screen_enum_init_memory(penum, porder, igs, psp, mem); if (code < 0) { screen_cleanup(i_ctx_p); return code; } /* Push everything on the estack */ make_mark_estack(esp + 1, es_other, screen_cleanup); esp += snumpush; make_op_estack(esp - 2, finish_proc); sproc = *pproc; push_op_estack(screen_sample); pop(npop); return o_push_estack; }
static int push_execstack(i_ctx_t *i_ctx_p, os_ptr op1, bool include_marks, op_proc_t cont) { uint size; /* * We can't do this directly, because the interpreter * might have cached some state. To force the interpreter * to update the stored state, we push a continuation on * the exec stack; the continuation is executed immediately, * and does the actual transfer. */ uint depth; if (!r_is_array(op1)) return_op_typecheck(op1); /* Check the length before the write access per CET 28-03 */ size = r_size(op1); depth = count_exec_stack(i_ctx_p, include_marks); if (depth > size) return_error(e_rangecheck); check_write(*op1); { int code = ref_stack_store_check(&e_stack, op1, size, 0); if (code < 0) return code; } check_estack(1); r_set_size(op1, depth); push_op_estack(cont); return o_push_estack; }
/* Set up the next sample */ static int screen_sample(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_screen_enum *penum = senum; gs_point pt; int code = gs_screen_currentpoint(penum, &pt); ref proc; switch (code) { default: return code; case 1: /* All done */ if (real_opproc(esp - 2) != 0) code = (*real_opproc(esp - 2)) (i_ctx_p); esp -= snumpush; screen_cleanup(i_ctx_p); return (code < 0 ? code : o_pop_estack); case 0: ; } push(2); make_real(op - 1, pt.x); make_real(op, pt.y); proc = sproc; push_op_estack(set_screen_continue); *++esp = proc; return o_push_estack; }
/* Allocate, and prepare to load, the index or tint map. */ int zcs_begin_map(i_ctx_t *i_ctx_p, gs_indexed_map ** pmap, const ref * pproc, int num_entries, const gs_color_space * base_space, op_proc_t map1) { gs_memory_t *mem = gs_state_memory(igs); int space = imemory_space((gs_ref_memory_t *)mem); int num_components = cs_num_components(base_space); int num_values = num_entries * num_components; gs_indexed_map *map; int code = alloc_indexed_map(&map, num_values, mem, "setcolorspace(mapped)"); es_ptr ep; if (code < 0) return code; *pmap = map; /* Map the entire set of color indices. Since the */ /* o-stack may not be able to hold N*4096 values, we have */ /* to load them into the cache as they are generated. */ check_estack(num_csme + 1); /* 1 extra for map1 proc */ ep = esp += num_csme; make_int(ep + csme_num_components, num_components); make_struct(ep + csme_map, space, map); ep[csme_proc] = *pproc; make_int(ep + csme_hival, num_entries - 1); make_int(ep + csme_index, -1); push_op_estack(map1); return o_push_estack; }
/* Continuation operator for enumerating files */ static int file_continue(i_ctx_t *i_ctx_p) { os_ptr op = osp; es_ptr pscratch = esp - 2; file_enum *pfen = r_ptr(esp - 1, file_enum); long devlen = esp[-3].value.intval; gx_io_device *iodev = r_ptr(esp - 4, gx_io_device); uint len = r_size(pscratch); uint code; if (len < devlen) return_error(e_rangecheck); /* not even room for device len */ memcpy((char *)pscratch->value.bytes, iodev->dname, devlen); code = iodev->procs.enumerate_next(pfen, (char *)pscratch->value.bytes + devlen, len - devlen); if (code == ~(uint) 0) { /* all done */ esp -= 5; /* pop proc, pfen, devlen, iodev , mark */ return o_pop_estack; } else if (code > len) /* overran string */ return_error(e_rangecheck); else { push(1); ref_assign(op, pscratch); r_set_size(op, code + devlen); push_op_estack(file_continue); /* come again */ *++esp = pscratch[2]; /* proc */ return o_push_estack; } }
/* * Set up to collect the next sampled data value. */ static int sampled_data_sample(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_sampled_data_enum *penum = senum; ref proc; gs_function_Sd_params_t * params = (gs_function_Sd_params_t *)&penum->pfn->params; int num_inputs = params->m; int i; /* Put set of input values onto the stack. */ push(num_inputs); for (i = 0; i < num_inputs; i++) { double dmin = params->Domain[2 * i]; double dmax = params->Domain[2 * i + 1]; make_real(op - num_inputs + i + 1, (float) ( penum->indexes[i] * (dmax - dmin)/(params->Size[i] - 1) + dmin)); } proc = sample_proc; /* Get procedure from storage */ push_op_estack(sampled_data_continue); /* Put 'save' routine on estack, after sample proc */ *++esp = proc; /* Put procedure to be executed */ return o_push_estack; }
static int zpathforall(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_path_enum *penum; int code; check_proc(op[-3]); check_proc(op[-2]); check_proc(op[-1]); check_proc(*op); check_estack(8); if ((penum = gs_path_enum_alloc(imemory, "pathforall")) == 0) return_error(e_VMerror); code = gs_path_enum_init(penum, igs); if (code < 0) { ifree_object(penum, "path_cleanup"); return code; } /* Push a mark, the four procedures, and the path enumerator. */ push_mark_estack(es_for, path_cleanup); /* iterator */ memcpy(esp + 1, op - 3, 4 * sizeof(ref)); /* 4 procs */ esp += 5; make_istruct(esp, 0, penum); push_op_estack(path_continue); pop(4); op -= 4; return o_push_estack; }
/* <obj> <result> <mask> .stopped <result> */ static int zzstopped(i_ctx_t *i_ctx_p) { os_ptr op = osp; check_type(*op, t_integer); check_op(3); /* Mark the execution stack, and push the default result */ /* in case control returns normally. */ check_estack(5); push_mark_estack(es_stopped, no_cleanup); *++esp = op[-1]; /* save the result */ *++esp = *op; /* save the signal mask */ push_op_estack(stopped_push); push_op_estack(zexec); /* execute the operand */ pop(2); return o_push_estack; }
/* the stacks would get restored in case of an error. */ static int zstopped(i_ctx_t *i_ctx_p) { os_ptr op = osp; check_op(1); /* Mark the execution stack, and push the default result */ /* in case control returns normally. */ check_estack(5); push_mark_estack(es_stopped, no_cleanup); ++esp; make_false(esp); /* save the result */ ++esp; make_int(esp, 1); /* save the signal mask */ push_op_estack(stopped_push); push_op_estack(zexec); /* execute the operand */ return o_push_estack; }
static int zwritecvp_at(i_ctx_t *i_ctx_p, os_ptr op, uint start, bool first) { stream *s; byte str[100]; /* arbitrary */ ref rstr; const byte *data = str; uint len; int code, status; check_write_file(s, op - 2); check_type(*op, t_integer); code = obj_cvp(op - 1, str, sizeof(str), &len, (int)op->value.intval, start, imemory, true); if (code == e_rangecheck) { code = obj_string_data(imemory, op - 1, &data, &len); if (len < start) return_error(e_rangecheck); data += start; len -= start; } if (code < 0) return code; r_set_size(&rstr, len); rstr.value.const_bytes = data; status = write_string(&rstr, s); switch (status) { default: return_error(e_ioerror); case 0: break; case INTC: case CALLC: len = start + len - r_size(&rstr); if (!first) --osp; /* pop(1) without affecting op */ return handle_write_status(i_ctx_p, status, op - 2, &len, zwritecvp_continue); } if (code == 1) { if (first) check_ostack(1); push_op_estack(zwritecvp_continue); if (first) push(1); make_int(osp, start + len); return o_push_estack; } if (first) /* zwritecvp */ pop(3); else /* zwritecvp_continue */ pop(4); return 0; }
/* <executable_file> .execfile - */ static int zexecfile(i_ctx_t *i_ctx_p) { os_ptr op = osp; check_type_access(*op, t_file, a_executable | a_read | a_execute); check_estack(4); /* cleanup, file, finish, file */ push_mark_estack(es_other, execfile_cleanup); *++esp = *op; push_op_estack(execfile_finish); return zexec(i_ctx_p); }
/* * Set up to collect the data for the sampled function. This is used for * those alternate tint transforms that cannot be converted into a * type 4 function. */ static int sampled_data_setup(i_ctx_t *i_ctx_p, gs_function_t *pfn, const ref * pproc, int (*finish_proc)(i_ctx_t *), gs_memory_t * mem) { os_ptr op = osp; gs_sampled_data_enum *penum; int i; gs_function_Sd_params_t * params = (gs_function_Sd_params_t *)&pfn->params; check_estack(estack_storage + 1); /* Verify space on estack */ check_ostack(params->m + O_STACK_PAD); /* and the operand stack */ check_ostack(params->n + O_STACK_PAD); /* * Allocate space for the enumerator data structure. */ penum = gs_sampled_data_enum_alloc(imemory, "zbuildsampledfuntion(params)"); if (penum == NULL) return_error(e_VMerror); /* Initialize data in the enumeration structure */ penum->pfn = pfn; for(i=0; i< params->m; i++) penum->indexes[i] = 0; /* * Save stack depth for checking the correct number of values on stack * after the function, which is being sampled, is called. */ penum->o_stack_depth = ref_stack_count(&o_stack); /* * Note: As previously mentioned, we are putting some spare (unused) stack * space under the input values in case the function unbalances the stack. * It is possible for the function to pop or change values on the stack * outside of the input values. (This has been found to happen with some * proc sets from Adobe.) */ push(O_STACK_PAD); for (i = 0; i < O_STACK_PAD; i++) /* Set space = null */ make_null(op - i); /* Push everything on the estack */ esp += estack_storage; make_op_estack(esp - 2, finish_proc); /* Finish proc onto estack */ sample_proc = *pproc; /* Save function to be sampled */ make_istruct(esp, 0, penum); /* Color cube enumeration structure */ push_op_estack(sampled_data_sample); /* Start sampling data */ return o_push_estack; }
/* <redproc> <greenproc> <blueproc> <grayproc> setcolortransfer - */ static int zsetcolortransfer(i_ctx_t *i_ctx_p) { os_ptr op = osp; int code; check_proc(op[-3]); check_proc(op[-2]); check_proc(op[-1]); check_proc(*op); check_ostack(zcolor_remap_one_ostack * 4 - 4); check_estack(1 + zcolor_remap_one_estack * 4); istate->transfer_procs.red = op[-3]; istate->transfer_procs.green = op[-2]; istate->transfer_procs.blue = op[-1]; istate->transfer_procs.gray = *op; if ((code = gs_setcolortransfer_remap(igs, gs_mapped_transfer, gs_mapped_transfer, gs_mapped_transfer, gs_mapped_transfer, false)) < 0 ) return code; /* Use osp rather than op here, because zcolor_remap_one pushes. */ pop(4); push_op_estack(zcolor_reset_transfer); if ((code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.red, igs->set_transfer.red, igs, zcolor_remap_one_finish)) < 0 || (code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.green, igs->set_transfer.green, igs, zcolor_remap_one_finish)) < 0 || (code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.blue, igs->set_transfer.blue, igs, zcolor_remap_one_finish)) < 0 || (code = zcolor_remap_one(i_ctx_p, &istate->transfer_procs.gray, igs->set_transfer.gray, igs, zcolor_remap_one_finish)) < 0 ) return code; return o_push_estack; }
/* <proc> setblackgeneration - */ static int zsetblackgeneration(i_ctx_t *i_ctx_p) { os_ptr op = osp; int code; check_proc(*op); check_ostack(zcolor_remap_one_ostack - 1); check_estack(1 + zcolor_remap_one_estack); code = gs_setblackgeneration_remap(igs, gs_mapped_transfer, false); if (code < 0) return code; istate->black_generation = *op; pop(1); push_op_estack(zcolor_remap_color); return zcolor_remap_one(i_ctx_p, &istate->black_generation, igs->black_generation, igs, zcolor_remap_one_finish); }
/* * Push a continuation, the arguments removed for the OtherSubr, and * the OtherSubr procedure. */ static int type1_push_OtherSubr(i_ctx_t *i_ctx_p, const gs_type1exec_state *pcxs, int (*cont)(i_ctx_t *), const ref *pos) { int i, n = pcxs->num_args; push_op_estack(cont); /* * Push the saved arguments (in reverse order, so they will get put * back on the operand stack in the correct order) on the e-stack. */ for (i = n; --i >= 0; ) { *++esp = pcxs->save_args[i]; r_clear_attrs(esp, a_executable); /* just in case */ } ++esp; *esp = *pos; return o_push_estack; }
/* <proc> setundercolorremoval - */ static int zsetundercolorremoval(i_ctx_t *i_ctx_p) { os_ptr op = osp; int code; check_proc(*op); check_ostack(zcolor_remap_one_ostack - 1); check_estack(1 + zcolor_remap_one_estack); code = gs_setundercolorremoval_remap(igs, gs_mapped_transfer, false); if (code < 0) return code; istate->undercolor_removal = *op; pop(1); push_op_estack(zcolor_remap_color); return zcolor_remap_one(i_ctx_p, &istate->undercolor_removal, igs->undercolor_removal, igs, zcolor_remap_one_signed_finish); }
static int image_proc_process(i_ctx_t *i_ctx_p) { int px = ETOP_PLANE_INDEX(esp)->value.intval; gs_image_enum *penum = r_ptr(esp, gs_image_enum); const byte *wanted = gs_image_planes_wanted(penum); int num_sources = ETOP_NUM_SOURCES(esp)->value.intval; const ref *pp; ETOP_SOURCE(esp, 0)[1].value.intval = 0; /* procedure callout */ while (!wanted[px]) { if (++px == num_sources) px = 0; ETOP_PLANE_INDEX(esp)->value.intval = px; } pp = ETOP_SOURCE(esp, px); push_op_estack(image_proc_continue); *++esp = *pp; return o_push_estack; }
static int path_continue(i_ctx_t *i_ctx_p) { gs_path_enum *penum = r_ptr(esp, gs_path_enum); gs_point ppts[3]; int code; /* Make sure we have room on the o-stack for the worst case */ /* before we enumerate the next path element. */ check_ostack(6); /* 3 points for curveto */ code = gs_path_enum_next(penum, ppts); switch (code) { case 0: /* all done */ esp -= 6; path_cleanup(i_ctx_p); return o_pop_estack; default: /* error */ return code; case gs_pe_moveto: esp[2] = esp[-4]; /* moveto proc */ pf_push(i_ctx_p, ppts, 1); break; case gs_pe_lineto: esp[2] = esp[-3]; /* lineto proc */ pf_push(i_ctx_p, ppts, 1); break; case gs_pe_curveto: esp[2] = esp[-2]; /* curveto proc */ pf_push(i_ctx_p, ppts, 3); break; case gs_pe_closepath: esp[2] = esp[-1]; /* closepath proc */ break; } push_op_estack(path_continue); ++esp; /* include pushed procedure */ return o_push_estack; }
/* * 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; int have_cdevproc; ref rpop; 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); 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, pcnref); 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; }
/* * Note that op_show_continue_dispatch sets osp = op explicitly iff the * dispatch succeeds. This is so that the show operators don't pop anything * from the o-stack if they don't succeed. Note also that if it returns an * error, it has freed the enumerator. */ int op_show_continue_dispatch(i_ctx_t *i_ctx_p, int npop, int code) { os_ptr op = osp - npop; gs_text_enum_t *penum = senum; switch (code) { case 0: { /* all done */ os_ptr save_osp = osp; osp = op; code = (*real_opproc(&seproc)) (i_ctx_p); op_show_free(i_ctx_p, code); if (code < 0) { osp = save_osp; return code; } return o_pop_estack; } case TEXT_PROCESS_INTERVENE: { ref *pslot = &sslot; /* only used for kshow */ push(2); make_int(op - 1, gs_text_current_char(penum)); /* previous char */ make_int(op, gs_text_next_char(penum)); push_op_estack(op_show_continue); /* continue after kerning */ *++esp = *pslot; /* kerning procedure */ return o_push_estack; } case TEXT_PROCESS_RENDER: { gs_font *pfont = gs_currentfont(igs); font_data *pfdata = pfont_data(pfont); gs_char chr = gs_text_current_char(penum); gs_glyph glyph = gs_text_current_glyph(penum); push(2); op[-1] = pfdata->dict; /* push the font */ /* * For Type 1 and Type 4 fonts, prefer BuildChar to BuildGlyph * if there is no glyph, or if there is both a character and a * glyph and the glyph is the one that corresponds to the * character in the Encoding, so that PostScript procedures * appearing in the CharStrings dictionary will receive the * character code rather than the character name; for Type 3 * fonts, prefer BuildGlyph to BuildChar. For other font types * (such as CID fonts), only BuildGlyph will be present. */ if (pfont->FontType == ft_user_defined) { /* Type 3 font, prefer BuildGlyph. */ if (level2_enabled && !r_has_type(&pfdata->BuildGlyph, t_null) && glyph != gs_no_glyph ) { glyph_ref(imemory, glyph, op); esp[2] = pfdata->BuildGlyph; } else if (r_has_type(&pfdata->BuildChar, t_null)) goto err; else if (chr == gs_no_char) { /* glyphshow, reverse map the character */ /* through the Encoding */ ref gref; const ref *pencoding = &pfdata->Encoding; glyph_ref(imemory, glyph, &gref); if (!map_glyph_to_char(imemory, &gref, pencoding, (ref *) op) ) { /* Not found, try .notdef */ name_enter_string(imemory, ".notdef", &gref); if (!map_glyph_to_char(imemory, &gref, pencoding, (ref *) op) ) goto err; } esp[2] = pfdata->BuildChar; } else { make_int(op, chr & 0xff); esp[2] = pfdata->BuildChar; } } else { /* * For a Type 1 or Type 4 font, prefer BuildChar or * BuildGlyph as described above: we know that both * BuildChar and BuildGlyph are present. For other font * types, only BuildGlyph is available. */ ref eref, gref; if (chr != gs_no_char && !r_has_type(&pfdata->BuildChar, t_null) && (glyph == gs_no_glyph || (!r_has_type(&pfdata->Encoding, t_null) && array_get(imemory, &pfdata->Encoding, (long)(chr & 0xff), &eref) >= 0 && (glyph_ref(imemory, glyph, &gref), obj_eq(imemory, &gref, &eref)))) ) { make_int(op, chr & 0xff); esp[2] = pfdata->BuildChar; } else { /* We might not have a glyph: substitute 0. **HACK** */ if (glyph == gs_no_glyph) make_int(op, 0); else glyph_ref(imemory, glyph, op); esp[2] = pfdata->BuildGlyph; } } /* Save the stack depths in case we bail out. */ sodepth.value.intval = ref_stack_count(&o_stack) - 2; sddepth.value.intval = ref_stack_count(&d_stack); push_op_estack(op_show_continue); ++esp; /* skip BuildChar or BuildGlyph proc */ return o_push_estack; } case TEXT_PROCESS_CDEVPROC: { gs_font *pfont = penum->current_font; ref cnref; op_proc_t cont = op_show_continue, exec_cont = 0; gs_glyph glyph = penum->returned.current_glyph; int code; pop(npop); op = osp; glyph_ref(imemory, glyph, &cnref); if (pfont->FontType == ft_CID_TrueType) { gs_font_type42 *pfont42 = (gs_font_type42 *)pfont; uint glyph_index = pfont42->data.get_glyph_index(pfont42, glyph); code = zchar42_set_cache(i_ctx_p, (gs_font_base *)pfont42, &cnref, glyph_index, cont, &exec_cont); } else if (pfont->FontType == ft_CID_encrypted) code = z1_set_cache(i_ctx_p, (gs_font_base *)pfont, &cnref, glyph, cont, &exec_cont); else return_error(e_unregistered); /* Unimplemented. */ if (exec_cont != 0) return_error(e_unregistered); /* Must not happen. */ return code; } default: /* error */ err: if (code >= 0) code = gs_note_error(e_invalidfont); return op_show_free(i_ctx_p, code); } }
static int bbox_finish(i_ctx_t *i_ctx_p, op_proc_t cont, op_proc_t *exec_cont) { /* Returns exec_cont - a function, which must be called by caller after this function. */ os_ptr op = osp; gs_font *pfont; int code; gs_text_enum_t *penum = op_show_find(i_ctx_p); gs_type1exec_state cxs; /* stack allocate to avoid sandbars */ gs_type1_state *const pcis = &cxs.cis; double sbxy[2]; gs_point sbpt; gs_point *psbpt = 0; os_ptr opc = op; const ref *opstr; ref other_subr; if (!r_has_type(opc, t_string)) { check_op(3); code = num_params(op, 2, sbxy); if (code < 0) return code; sbpt.x = sbxy[0]; sbpt.y = sbxy[1]; psbpt = &sbpt; opc -= 2; check_type(*opc, t_string); } code = font_param(opc - 3, &pfont); if (code < 0) return code; if (penum == 0 || !font_uses_charstrings(pfont)) return_error(e_undefined); { gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont; int lenIV = pfont1->data.lenIV; if (lenIV > 0 && r_size(opc) <= lenIV) return_error(e_invalidfont); check_estack(5); /* in case we need to do a callout */ code = type1_exec_init(pcis, penum, igs, pfont1); if (code < 0) return code; if (psbpt) gs_type1_set_lsb(pcis, psbpt); } opstr = opc; icont: code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr, (psbpt ? 6 : 4)); op = osp; /* OtherSubrs might have altered it */ switch (code) { case 0: /* all done */ /* Call the continuation now. */ if (psbpt) pop(2); *exec_cont = cont; return 0; case type1_result_callothersubr: /* unknown OtherSubr */ push_op_estack(cont); /* call later */ return type1_call_OtherSubr(i_ctx_p, &cxs, bbox_continue, &other_subr); case type1_result_sbw: /* [h]sbw, just continue */ opstr = 0; goto icont; default: /* code < 0, error */ return code; } }
static int zimage_data_setup(i_ctx_t *i_ctx_p, const gs_pixel_image_t * pim, gx_image_enum_common_t * pie, const ref * sources, int npop) { int num_sources = pie->num_planes; int inumpush = NUM_PUSH(num_sources); int code; gs_image_enum *penum; int px; const ref *pp; bool string_sources = true; check_estack(inumpush + 2); /* stuff above, + continuation + proc */ make_int(EBOT_NUM_SOURCES(esp), num_sources); /* * Note that the data sources may be procedures, strings, or (Level * 2 only) files. (The Level 1 reference manual says that Level 1 * requires procedures, but Adobe Level 1 interpreters also accept * strings.) The sources must all be of the same type. * * The Adobe documentation explicitly says that if two or more of the * data sources are the same or inter-dependent files, the result is not * defined. We don't have a problem with the bookkeeping for * inter-dependent files, since each one has its own buffer, but we do * have to be careful if two or more sources are actually the same file. * That is the reason for the aliasing information described above. */ for (px = 0, pp = sources; px < num_sources; px++, pp++) { es_ptr ep = EBOT_SOURCE(esp, px); make_int(ep + 1, 1); /* default is no aliasing */ switch (r_type(pp)) { case t_file: if (!level2_enabled) return_error(e_typecheck); /* Check for aliasing. */ { int pi; for (pi = 0; pi < px; ++pi) if (sources[pi].value.pfile == pp->value.pfile) { /* Record aliasing */ make_int(ep + 1, -pi); EBOT_SOURCE(esp, pi)[1].value.intval++; break; } } string_sources = false; /* falls through */ case t_string: if (r_type(pp) != r_type(sources)) { if (pie != NULL) gx_image_end(pie, false); /* Clean up pie */ return_error(e_typecheck); } check_read(*pp); break; default: if (!r_is_proc(sources)) { static const char ds[] = "DataSource"; if (pie != NULL) gx_image_end(pie, false); /* Clean up pie */ gs_errorinfo_put_pair(i_ctx_p, ds, sizeof(ds) - 1, pp); return_error(e_typecheck); } check_proc(*pp); string_sources = false; } *ep = *pp; } /* Always place the image enumerator into local memory, because pie may have local objects inherited from igs, which may be local when the current allocation mode is global. Bug 688140. */ if ((penum = gs_image_enum_alloc(imemory_local, "image_setup")) == 0) return_error(e_VMerror); code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs); if (code != 0 || (pie->skipping && string_sources)) { /* error, or empty image */ int code1 = gs_image_cleanup_and_free_enum(penum, igs); if (code >= 0) /* empty image */ pop(npop); if (code >= 0 && code1 < 0) code = code1; return code; } push_mark_estack(es_other, image_cleanup); esp += inumpush - 1; make_int(ETOP_PLANE_INDEX(esp), 0); make_int(ETOP_NUM_SOURCES(esp), num_sources); make_struct(esp, avm_local, penum); switch (r_type(sources)) { case t_file: push_op_estack(image_file_continue); break; case t_string: push_op_estack(image_string_continue); break; default: /* procedure */ push_op_estack(image_proc_process); break; } pop(npop); return o_push_estack; }
/* * 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). */ int zchar_set_cache(os_ptr op, const gs_font_base *pbfont, const ref *pcnref, const float psb[2], const float pwidth[2], const gs_rect *pbbox, int (*cont_fill)(P1(os_ptr)), int (*cont_stroke)(P1(os_ptr))) { const ref *pfdict = &pfont_data(pbfont)->dict; ref *pmdict; ref *pcdevproc; int have_cdevproc; ref rpop; bool metrics2 = false; int (*cont)(P1(os_ptr)); float w2[10]; gs_show_enum *penum = op_show_find(); 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 ) cont = cont_fill; else { double expand = max(1.415, gs_currentmiterlimit(igs)) * gs_currentlinewidth(igs) / 2; w2[2] -= expand, w2[3] -= expand; w2[4] += expand, w2[5] += expand; cont = cont_stroke; } /* Check for Metrics2. */ 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, w2 + 6); if ( code < 0 ) return code; metrics2 = true; } } } /* Check for CDevProc or "short-circuiting". */ have_cdevproc = dict_find_string(pfdict, "CDevProc", &pcdevproc) > 0; if ( have_cdevproc || gs_show_width_only(penum) ) { int i; int (*zsetc)(P1(os_ptr)); int nparams; if ( have_cdevproc ) { check_proc_only(*pcdevproc); zsetc = zsetcachedevice2; if ( !metrics2 ) { 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, pcnref); push_op_estack(cont); push_op_estack(zsetc); ++esp; ref_assign(esp, pcdevproc); return o_push_estack; } { int code = (metrics2 ? gs_setcachedevice2(penum, igs, w2) : gs_setcachedevice(penum, igs, 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]); } return cont(op); }
/* * 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; }