/* Check whether color is a shading with BBox. */ int gx_dc_pattern2_is_rectangular_cell(const gx_device_color * pdevc, gx_device * pdev, gs_fixed_rect *rect) { if (gx_dc_is_pattern2_color(pdevc) && gx_dc_pattern2_color_has_bbox(pdevc) && (*dev_proc(pdev, dev_spec_op))(pdev, gxdso_pattern_shading_area, NULL, 0) == 0) { gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern; const gs_shading_t *psh = pinst->templat.Shading; gs_fixed_point p, q; if (is_xxyy(&ctm_only(pinst->saved))) if (psh->params.have_BBox) { int code = gs_point_transform2fixed(&pinst->saved->ctm, psh->params.BBox.p.x, psh->params.BBox.p.y, &p); if (code < 0) return code; code = gs_point_transform2fixed(&pinst->saved->ctm, psh->params.BBox.q.x, psh->params.BBox.q.y, &q); if (code < 0) return code; if (p.x > q.x) { p.x ^= q.x; q.x ^= p.x; p.x ^= q.x; } if (p.y > q.y) { p.y ^= q.y; q.y ^= p.y; p.y ^= q.y; } rect->p = p; rect->q = q; return 1; } } return 0; }
/* the character, as opposed to just computing the side bearing and width. */ void gs_type1_finish_init(gs_type1_state * pcis) { gs_imager_state *pis = pcis->pis; const int max_coeff_bits = 11; /* max coefficient in char space */ /* Set up the fixed version of the transformation. */ gx_matrix_to_fixed_coeff(&ctm_only(pis), &pcis->fc, max_coeff_bits); /* Set the current point of the path to the origin, */ pcis->origin.x = pcis->path->position.x; pcis->origin.y = pcis->path->position.y; /* Initialize hint-related scalars. */ pcis->asb_diff = pcis->adxy.x = pcis->adxy.y = 0; pcis->base_lsb = 0; pcis->flex_count = flex_max; /* not in Flex */ pcis->vs_offset.x = pcis->vs_offset.y = 0; /* Compute the flatness needed for accurate rendering. */ pcis->flatness = gs_char_flatness(pis, 0.001); pcis->init_done = 1; }
int gs_upathbbox(gs_state * pgs, gs_rect * pbox, bool include_moveto) { gs_fixed_rect fbox; /* box in device coordinates */ gs_rect dbox; int code = gx_path_bbox_set(pgs->path, &fbox); if (code < 0) return code; /* If the path ends with a moveto and include_moveto is true, */ /* include the moveto in the bounding box. */ if (path_last_is_moveto(pgs->path) && include_moveto) { gs_fixed_point pt; code = gx_path_current_point_inline(pgs->path, &pt); if (code < 0) return code; if (pt.x < fbox.p.x) fbox.p.x = pt.x; if (pt.y < fbox.p.y) fbox.p.y = pt.y; if (pt.x > fbox.q.x) fbox.q.x = pt.x; if (pt.y > fbox.q.y) fbox.q.y = pt.y; } /* Transform the result back to user coordinates. */ dbox.p.x = fixed2float(fbox.p.x); dbox.p.y = fixed2float(fbox.p.y); dbox.q.x = fixed2float(fbox.q.x); dbox.q.y = fixed2float(fbox.q.y); return gs_bbox_transform_inverse(&dbox, &ctm_only(pgs), pbox); }
int gs_itransform(gs_state * pgs, floatp x, floatp y, gs_point * pt) { /* If the matrix isn't skewed, we get more accurate results */ /* by using transform_inverse than by using the inverse matrix. */ if (!is_skewed(&pgs->ctm)) { return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt); } else { ensure_inverse_valid(pgs); return gs_point_transform(x, y, &pgs->ctm_inverse, pt); } }
static int ctm_set_inverse(gs_state * pgs) { int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse); print_inverse(pgs); if (code < 0) return code; pgs->ctm_inverse_valid = true; return 0; }
int gs_rotate(gs_state * pgs, floatp ang) { int code = gs_matrix_rotate(&ctm_only(pgs), ang, &ctm_only_writable(pgs)); pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false; #ifdef DEBUG if (gs_debug_c('x')) dlprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs); #endif return code; }
/* This is just a bridge to an old code. */ int gx_dc_pattern2_shade_bbox_transform2fixed(const gs_rect * rect, const gs_imager_state * pis, gs_fixed_rect * rfixed) { gs_rect dev_rect; int code = gs_bbox_transform(rect, &ctm_only(pis), &dev_rect); if (code >= 0) { rfixed->p.x = float2fixed(dev_rect.p.x); rfixed->p.y = float2fixed(dev_rect.p.y); rfixed->q.x = float2fixed(dev_rect.q.x); rfixed->q.y = float2fixed(dev_rect.q.y); } return code; }
int gs_concat(gs_state * pgs, const gs_matrix * pmat) { gs_matrix cmat; int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat); if (code < 0) return code; update_ctm(pgs, cmat.tx, cmat.ty); set_ctm_only(pgs, cmat); #ifdef DEBUG if (gs_debug_c('x')) dlprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs); #endif return code; }
RELOC_PTRS_END static int is_image_visible(const gs_image_common_t * pic, gs_state * pgs, gx_clip_path *pcpath) { /* HACK : We need the source image size here, but gs_image_common_t doesn't pass it. We would like to move Width, Height to gs_image_common, but gs_image2_t appears to have those fields of double type. */ if (pic->type->begin_typed_image == gx_begin_image1) { gs_image1_t *pim = (gs_image1_t *) pic; gs_rect image_rect = {{0, 0}, {0, 0}}; gs_rect device_rect; gs_int_rect device_int_rect; gs_matrix mat; int code; image_rect.q.x = pim->Width; image_rect.q.y = pim->Height; if (pic->ImageMatrix.xx == ctm_only(pgs).xx && pic->ImageMatrix.xy == ctm_only(pgs).xy && pic->ImageMatrix.yx == ctm_only(pgs).yx && pic->ImageMatrix.yy == ctm_only(pgs).yy) { /* Handle common special case separately to accept singular matrix */ mat.xx = mat.yy = 1.; mat.yx = mat.xy = 0.; mat.tx = ctm_only(pgs).tx - pic->ImageMatrix.tx; mat.ty = ctm_only(pgs).ty - pic->ImageMatrix.ty; } else { code = gs_matrix_invert(&pic->ImageMatrix, &mat); if (code < 0) return code; code = gs_matrix_multiply(&mat, &ctm_only(pgs), &mat); if (code < 0) return code; } code = gs_bbox_transform(&image_rect, &mat, &device_rect); if (code < 0) return code; device_int_rect.p.x = (int)floor(device_rect.p.x); device_int_rect.p.y = (int)floor(device_rect.p.y); device_int_rect.q.x = (int)ceil(device_rect.q.x); device_int_rect.q.y = (int)ceil(device_rect.q.y); if (!gx_cpath_rect_visible(pcpath, &device_int_rect)) return 0; } return 1; }
void xps_bounds_in_user_space(xps_context_t *ctx, gs_rect *ubox) { gx_clip_path *clip_path; gs_rect dbox; int code; code = gx_effective_clip_path(ctx->pgs, &clip_path); if (code < 0) gs_warn("gx_effective_clip_path failed"); dbox.p.x = fixed2float(clip_path->outer_box.p.x); dbox.p.y = fixed2float(clip_path->outer_box.p.y); dbox.q.x = fixed2float(clip_path->outer_box.q.x); dbox.q.y = fixed2float(clip_path->outer_box.q.y); gs_bbox_transform_inverse(&dbox, &ctm_only(ctx->pgs), ubox); }
/* The caller must supply a string to the first call of gs_type1_interpret. */ int gs_type1_init(register gs_type1_state *pis, gs_show_enum *penum, int charpath_flag, int paint_type, gs_type1_data *pdata) { gs_state *pgs = penum->pgs; pis->penum = penum; pis->pgs = pgs; pis->pdata = pdata; pis->charpath_flag = charpath_flag; pis->paint_type = paint_type; pis->os_count = 0; pis->ips_count = 1; pis->seac_base = -1; pis->in_dotsection = 0; pis->vstem3_set = 0; pis->vs_offset.x = pis->vs_offset.y = 0; reset_stem_hints(pis); gx_matrix_to_fixed_coeff(&ctm_only(pgs), &pis->fc, max_coeff_bits); compute_font_hints(&pis->fh, &pgs->ctm, pdata); /* Set the current point of the path to the origin, */ /* in anticipation of the initial [h]sbw. */ { gx_path *ppath = pgs->path; ppath->position.x = pgs->ctm.tx_fixed; ppath->position.y = pgs->ctm.ty_fixed; } /* Set the flatness to a value that is likely to produce */ /* reasonably good-looking curves, regardless of its */ /* current value in the graphics state. */ { /* If the character is very small, set the flatness */ /* to zero, which will produce very accurate curves. */ float cxx = pgs->ctm.xx, cyy = pgs->ctm.yy; if ( cxx < 0 ) cxx = -cxx; if ( cyy < 0 ) cyy = -cyy; if ( cyy > cxx ) cxx = cyy; if ( is_skewed(&pgs->ctm) ) { float cxy = pgs->ctm.xy, cyx = pgs->ctm.yx; if ( cxy < 0 ) cxy = -cxy; if ( cyx < 0 ) cyx = -cyx; if ( cxy > cxx ) cxx = cxy; if ( cyx > cxx ) cxx = cyx; } /* Now cxx is approximately one character space unit */ /* in device pixels. */ pis->flatness = (cxx >= 0.2 ? cxx : 0.0); } return 0; }
/* Note that this may be based on a font other than the current font. */ int gs_setcharmatrix(gs_state * pgs, const gs_matrix * pmat) { gs_matrix cmat; int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat); if (code < 0) return code; update_matrix_fixed(pgs->char_tm, cmat.tx, cmat.ty); char_tm_only(pgs) = cmat; #ifdef DEBUG if (gs_debug_c('x')) dlprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm); #endif pgs->char_tm_valid = true; return 0; }
/* Set the bounding box for the current path. */ int gs_setbbox(gs_state * pgs, double llx, double lly, double urx, double ury) { gs_rect ubox, dbox; gs_fixed_rect obox, bbox; gx_path *ppath = pgs->path; int code; if (llx > urx || lly > ury) return_error(gs_error_rangecheck); /* Transform box to device coordinates. */ ubox.p.x = llx; ubox.p.y = lly; ubox.q.x = urx; ubox.q.y = ury; if ((code = gs_bbox_transform(&ubox, &ctm_only(pgs), &dbox)) < 0) return code; /* Round the corners in opposite directions. */ /* Because we can't predict the magnitude of the dbox values, */ /* we add/subtract the slop after fixing. */ if (dbox.p.x < fixed2float(min_fixed + box_rounding_slop_fixed) || dbox.p.y < fixed2float(min_fixed + box_rounding_slop_fixed) || dbox.q.x >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon) || dbox.q.y >= fixed2float(max_fixed - box_rounding_slop_fixed + fixed_epsilon) ) return_error(gs_error_limitcheck); bbox.p.x = (fixed) floor(dbox.p.x * fixed_scale) - box_rounding_slop_fixed; bbox.p.y = (fixed) floor(dbox.p.y * fixed_scale) - box_rounding_slop_fixed; bbox.q.x = (fixed) ceil(dbox.q.x * fixed_scale) + box_rounding_slop_fixed; bbox.q.y = (fixed) ceil(dbox.q.y * fixed_scale) + box_rounding_slop_fixed; if (gx_path_bbox_set(ppath, &obox) >= 0) { /* Take the union of the bboxes. */ ppath->bbox.p.x = min(obox.p.x, bbox.p.x); ppath->bbox.p.y = min(obox.p.y, bbox.p.y); ppath->bbox.q.x = max(obox.q.x, bbox.q.x); ppath->bbox.q.y = max(obox.q.y, bbox.q.y); } else { /* empty path *//* Just set the bbox. */ ppath->bbox = bbox; } ppath->bbox_set = 1; return 0; }
static inline int gs_arc_add_inline(gs_state *pgs, bool cw, floatp xc, floatp yc, floatp rad, floatp a1, floatp a2, bool add) { gs_point p3; int code = gs_imager_arc_add(pgs->path, (gs_imager_state *)pgs, cw, xc, yc, rad, a1, a2, add, &p3); if (code < 0) return code; #if !PRECISE_CURRENTPOINT return gx_setcurrentpoint_from_path((gs_imager_state *)pgs, pgs->path); #else pgs->current_point_valid = true; return gs_point_transform(p3.x, p3.y, &ctm_only(pgs), &pgs->current_point); #endif }
int gs_translate(gs_state * pgs, floatp dx, floatp dy) { gs_point pt; int code; if ((code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0) return code; pt.x = (float)pt.x + pgs->ctm.tx; pt.y = (float)pt.y + pgs->ctm.ty; update_ctm(pgs, pt.x, pt.y); #ifdef DEBUG if (gs_debug_c('x')) dlprintf4("[x]translate: %f %f -> %f %f\n", dx, dy, pt.x, pt.y), trace_ctm(pgs); #endif return 0; }
static int bbox_image_begin(const gs_imager_state * pis, const gs_matrix * pmat, const gs_image_common_t * pic, const gs_int_rect * prect, const gx_clip_path * pcpath, gs_memory_t * memory, bbox_image_enum ** ppbe) { int code; gs_matrix mat; bbox_image_enum *pbe; if (pmat == 0) pmat = &ctm_only(pis); if ((code = gs_matrix_invert(&pic->ImageMatrix, &mat)) < 0 || (code = gs_matrix_multiply(&mat, pmat, &mat)) < 0 ) return code; pbe = gs_alloc_struct(memory, bbox_image_enum, &st_bbox_image_enum, "bbox_image_begin"); if (pbe == 0) return_error(gs_error_VMerror); pbe->memory = memory; pbe->matrix = mat; pbe->pcpath = pcpath; pbe->target_info = 0; /* in case no target */ pbe->params_are_const = false; /* check the first time */ if (prect) { pbe->x0 = prect->p.x, pbe->x1 = prect->q.x; pbe->y = prect->p.y, pbe->height = prect->q.y - prect->p.y; } else { gs_int_point size; int code = (*pic->type->source_size) (pis, pic, &size); if (code < 0) { gs_free_object(memory, pbe, "bbox_image_begin"); return code; } pbe->x0 = 0, pbe->x1 = size.x; pbe->y = 0, pbe->height = size.y; } *ppbe = pbe; return 0; }
static int pdf_make_form_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams, const gs_imager_state * pis, const cos_dict_t *group_dict, cos_dict_t *form_dict) { cos_array_t *bbox_array; float bbox[4]; gs_rect bbox_rect; int code; code = gs_bbox_transform(&pparams->bbox, &ctm_only(pis), &bbox_rect); if (code < 0) return code; bbox[0] = bbox_rect.p.x; bbox[1] = bbox_rect.p.y; bbox[2] = bbox_rect.q.x; bbox[3] = bbox_rect.q.y; code = cos_dict_put_c_key_string(form_dict, "/Type", (const byte *)"/XObject", 8); if (code < 0) return code; code = cos_dict_put_c_key_string(form_dict, "/Subtype", (const byte *)"/Form", 5); if (code < 0) return code; code = cos_dict_put_c_key_int(form_dict, "/FormType", 1); if (code < 0) return code; code = cos_dict_put_c_key_string(form_dict, "/Matrix", (const byte *)"[1 0 0 1 0 0]", 13); if (code < 0) return code; bbox_array = cos_array_from_floats(pdev, bbox, 4, "pdf_begin_transparency_group"); if (bbox_array == NULL) return_error(gs_error_VMerror); code = cos_dict_put_c_key_object(form_dict, "/BBox", (cos_object_t *)bbox_array); if (code < 0) return code; return cos_dict_put_c_key_object(form_dict, "/Group", (cos_object_t *)group_dict); }
/* Internal routine for adding an arc to the path. */ static int arc_add(const arc_curve_params_t * arc, bool is_quadrant) { gx_path *path = arc->ppath; gs_imager_state *pis = arc->pis; double x0 = arc->p0.x, y0 = arc->p0.y; double xt = arc->pt.x, yt = arc->pt.y; floatp fraction; gs_fixed_point p0, p2, p3, pt; int code; if ((arc->action != arc_nothing && #if !PRECISE_CURRENTPOINT (code = gs_point_transform2fixed(&pis->ctm, x0, y0, &p0)) < 0) || (code = gs_point_transform2fixed(&pis->ctm, xt, yt, &pt)) < 0 || (code = gs_point_transform2fixed(&pis->ctm, arc->p3.x, arc->p3.y, &p3)) < 0 #else (code = gs_point_transform2fixed_rounding(&pis->ctm, x0, y0, &p0)) < 0) || (code = gs_point_transform2fixed_rounding(&pis->ctm, xt, yt, &pt)) < 0 || (code = gs_point_transform2fixed_rounding(&pis->ctm, arc->p3.x, arc->p3.y, &p3)) < 0 #endif ) return code; #if PRECISE_CURRENTPOINT if (!path_position_valid(path)) gs_point_transform(arc->p0.x, arc->p0.y, &ctm_only(arc->pis), &pis->subpath_start); #endif code = (arc->action == arc_nothing ? (p0.x = path->position.x, p0.y = path->position.y, 0) : arc->action == arc_lineto && path_position_valid(path) ? gx_path_add_line(path, p0.x, p0.y) : /* action == arc_moveto, or lineto with no current point */ gx_path_add_point(path, p0.x, p0.y)); if (code < 0) return code; /* Compute the fraction coefficient for the curve. */ /* See gx_path_add_partial_arc for details. */ if (is_quadrant) { /* one of |dx| and |dy| is r, the other is zero */ fraction = quarter_arc_fraction; if (arc->fast_quadrant > 0) { /* * The CTM is well-behaved, and we have pre-calculated the delta * from the circumference points to the control points. */ fixed delta = arc->quadrant_delta; if (pt.x != p0.x) p0.x = (pt.x > p0.x ? p0.x + delta : p0.x - delta); if (pt.y != p0.y) p0.y = (pt.y > p0.y ? p0.y + delta : p0.y - delta); p2.x = (pt.x == p3.x ? p3.x : pt.x > p3.x ? p3.x + delta : p3.x - delta); p2.y = (pt.y == p3.y ? p3.y : pt.y > p3.y ? p3.y + delta : p3.y - delta); goto add; } } else { double r = arc->radius; floatp dx = xt - x0, dy = yt - y0; double dist = dx * dx + dy * dy; double r2 = r * r; if (dist >= r2 * 1.0e8) /* almost zero radius; */ /* the >= catches dist == r == 0 */ fraction = 0.0; else fraction = (4.0 / 3.0) / (1 + sqrt(1 + dist / r2)); } p0.x += (fixed)((pt.x - p0.x) * fraction); p0.y += (fixed)((pt.y - p0.y) * fraction); p2.x = p3.x + (fixed)((pt.x - p3.x) * fraction); p2.y = p3.y + (fixed)((pt.y - p3.y) * fraction); add: if_debug8('r', "[r]Arc f=%f p0=(%f,%f) pt=(%f,%f) p3=(%f,%f) action=%d\n", fraction, x0, y0, xt, yt, arc->p3.x, arc->p3.y, (int)arc->action); /* Open-code gx_path_add_partial_arc_notes */ return gx_path_add_curve_notes(path, p0.x, p0.y, p2.x, p2.y, p3.x, p3.y, arc->notes | sn_from_arc); }
char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */ sprintf(buf, "/R%ld Do\n", pcs_image->id); cos_stream_add_bytes(pcos, (const byte *)buf, strlen(buf)); } return 0; } /* Store pattern 1 parameters to cos dictionary. */ int pdf_store_pattern1_params(gx_device_pdf *pdev, pdf_resource_t *pres, gs_pattern1_instance_t *pinst) { gs_pattern1_template_t *t = &pinst->template; gs_matrix smat = ctm_only((gs_imager_state *)pinst->saved); double scale_x = pdev->HWResolution[0] / 72.0; double scale_y = pdev->HWResolution[1] / 72.0; cos_dict_t *pcd = cos_stream_dict((cos_stream_t *)pres->object); cos_dict_t *pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)"); float bbox[4]; int code; if (pcd == NULL || pcd_Resources == NULL) return_error(gs_error_VMerror); pdev->substream_Resources = pcd_Resources; bbox[0] = t->BBox.p.x; bbox[1] = t->BBox.p.y; bbox[2] = t->BBox.q.x; bbox[3] = t->BBox.q.y; /* The graphics library assumes a shifted origin to provide
int gs_dtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt) { return gs_distance_transform(dx, dy, &ctm_only(pgs), pt); }
int gs_transform(gs_state * pgs, floatp x, floatp y, gs_point * pt) { return gs_point_transform(x, y, &ctm_only(pgs), pt); }
int xps_high_level_pattern(xps_context_t *ctx) { gs_matrix m; gs_rect bbox; gs_fixed_rect clip_box; int code; gx_device_color *pdc = gs_currentdevicecolor_inline(ctx->pgs); const gs_client_pattern *ppat = gs_getpattern(&pdc->ccolor); gs_pattern1_instance_t *pinst = (gs_pattern1_instance_t *)gs_currentcolor(ctx->pgs)->pattern; code = gx_pattern_cache_add_dummy_entry((gs_imager_state *)ctx->pgs, pinst, ctx->pgs->device->color_info.depth); if (code < 0) return code; code = gs_gsave(ctx->pgs); if (code < 0) return code; dev_proc(ctx->pgs->device, get_initial_matrix)(ctx->pgs->device, &m); gs_setmatrix(ctx->pgs, &m); code = gs_bbox_transform(&ppat->BBox, &ctm_only(ctx->pgs), &bbox); if (code < 0) { gs_grestore(ctx->pgs); return code; } clip_box.p.x = float2fixed(bbox.p.x); clip_box.p.y = float2fixed(bbox.p.y); clip_box.q.x = float2fixed(bbox.q.x); clip_box.q.y = float2fixed(bbox.q.y); code = gx_clip_to_rectangle(ctx->pgs, &clip_box); if (code < 0) { gs_grestore(ctx->pgs); return code; } { pattern_accum_param_s param; param.pinst = (void *)pinst; param.graphics_state = (void *)ctx->pgs; param.pinst_id = pinst->id; code = (*dev_proc(ctx->pgs->device, dev_spec_op))((gx_device *)ctx->pgs->device, gxdso_pattern_start_accum, ¶m, sizeof(pattern_accum_param_s)); } if (code < 0) { gs_grestore(ctx->pgs); return code; } code = xps_paint_tiling_brush(&pdc->ccolor, ctx->pgs); if (code) { gs_grestore(ctx->pgs); return gs_rethrow(code, "high level pattern brush function failed"); } code = gs_grestore(ctx->pgs); if (code < 0) return code; { pattern_accum_param_s param; param.pinst = (void *)pinst; param.graphics_state = (void *)ctx->pgs; param.pinst_id = pinst->id; code = (*dev_proc(ctx->pgs->device, dev_spec_op))((gx_device *)ctx->pgs->device, gxdso_pattern_finish_accum, ¶m, sizeof(pattern_accum_param_s)); } return code; }
static int charstring_execchar_aux(i_ctx_t *i_ctx_p, gs_text_enum_t *penum, gs_font *pfont) { os_ptr op = osp; gs_font_base *const pbfont = (gs_font_base *) pfont; gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont; const gs_type1_data *pdata; gs_type1exec_state cxs; gs_type1_state *const pcis = &cxs.cis; gs_rect FontBBox = pfont1->FontBBox; int code; if (penum->current_font->FontType == ft_CID_encrypted) { if (FontBBox.q.x <= FontBBox.p.x && FontBBox.q.y <= FontBBox.p.y) { gs_font_cid0 *pfcid0 = (gs_font_cid0 *)penum->current_font; FontBBox = pfcid0->FontBBox; } } pdata = &pfont1->data; /* * Any reasonable implementation would execute something like * 1 setmiterlimit 0 setlinejoin 0 setlinecap * here, but the Adobe implementations don't. * * If this is a stroked font, set the stroke width. */ if (pfont->PaintType) gs_setlinewidth(igs, pfont->StrokeWidth); check_estack(3); /* for continuations */ /* * Execute the definition of the character. */ if (r_is_proc(op)) return zchar_exec_char_proc(i_ctx_p); /* * The definition must be a Type 1 CharString. * Note that we do not require read access: this is deliberate. */ check_type(*op, t_string); if (r_size(op) <= max(pdata->lenIV, 0)) return_error(e_invalidfont); /* * In order to make character oversampling work, we must * set up the cache before calling .type1addpath. * To do this, we must get the bounding box from the FontBBox, * and the width from the CharString or the Metrics. * If the FontBBox isn't valid, we can't do any of this. */ if ((penum->FontBBox_as_Metrics2.x == 0 && penum->FontBBox_as_Metrics2.y == 0) || gs_rootfont(igs)->WMode == 0 ) { code = zchar_get_metrics(pbfont, op - 1, cxs.sbw); if (code < 0) return code; cxs.present = code; cxs.use_FontBBox_as_Metrics2 = false; } else { /* pass here if FontType==9,11 && WMode==1*/ cxs.sbw[0] = penum->FontBBox_as_Metrics2.x / 2; cxs.sbw[1] = penum->FontBBox_as_Metrics2.y; cxs.sbw[2] = 0; cxs.sbw[3] = -penum->FontBBox_as_Metrics2.x; /* Sic! */ cxs.use_FontBBox_as_Metrics2 = true; cxs.present = metricsNone; } /* Establish a current point. */ code = gs_moveto(igs, 0.0, 0.0); if (code < 0) return code; code = type1_exec_init(pcis, penum, igs, pfont1); if (code < 0) return code; gs_type1_set_callback_data(pcis, &cxs); if (FontBBox.q.x > FontBBox.p.x && FontBBox.q.y > FontBBox.p.y ) { /* The FontBBox appears to be valid. */ op_proc_t exec_cont = 0; cxs.char_bbox = pfont1->FontBBox; code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont); if (code >= 0 && exec_cont != 0) code = (*exec_cont)(i_ctx_p); return code; } else { /* The FontBBox is not valid */ const ref *opstr = op; ref other_subr; const gs_matrix * pctm = &ctm_only(igs); /* First, check for singular CTM */ if (pctm->xx * pctm->yy == pctm->xy * pctm->yx) { /* The code below won't be able to find the FontBBox but we * don't need it anyway. Set an empty box and consider it valid. */ op_proc_t exec_cont = 0; cxs.char_bbox.p.x = 0; cxs.char_bbox.p.y = 0; cxs.char_bbox.q.x = 0; cxs.char_bbox.q.y = 0; code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont); if (code >= 0 && exec_cont != 0) code = (*exec_cont)(i_ctx_p); return code; } /* Now we create the path first, then do the setcachedevice. * If we are oversampling (in this case, only for anti- * aliasing, not just to improve quality), we have to * create the path twice, since we can't know the * oversampling factor until after setcachedevice. */ switch (cxs.present) { case metricsSideBearingAndWidth: { gs_point pt; pt.x = cxs.sbw[0], pt.y = cxs.sbw[1]; gs_type1_set_lsb(pcis, &pt); } /* fall through */ case metricsWidthOnly: { gs_point pt; pt.x = cxs.sbw[2], pt.y = cxs.sbw[3]; gs_type1_set_width(pcis, &pt); } } /* Continue interpreting. */ icont: code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr, 4); op = osp; /* OtherSubrs might change it */ switch (code) { case 0: /* all done */ return nobbox_finish(i_ctx_p, &cxs); default: /* code < 0, error */ return code; case type1_result_callothersubr: /* unknown OtherSubr */ return type1_call_OtherSubr(i_ctx_p, &cxs, nobbox_continue, &other_subr); case type1_result_sbw: /* [h]sbw, just continue */ switch (cxs.present) { case metricsNone: cxs.sbw[0] = fixed2float(pcis->lsb.x); cxs.sbw[1] = fixed2float(pcis->lsb.y); /* fall through */ case metricsWidthOnly: cxs.sbw[2] = fixed2float(pcis->width.x); cxs.sbw[3] = fixed2float(pcis->width.y); } opstr = 0; goto icont; } } }
int gs_imager_idtransform(const gs_imager_state * pis, floatp dx, floatp dy, gs_point * pt) { return gs_distance_transform_inverse(dx, dy, &ctm_only(pis), pt); }
/* * Continue interpreting a Type 2 charstring. If str != 0, it is taken as * the byte string to interpret. Return 0 on successful completion, <0 on * error, or >0 when client intervention is required (or allowed). The int* * argument is only for compatibility with the Type 1 charstring interpreter. */ int gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd, int *ignore_pindex) { gs_font_type1 *pfont = pcis->pfont; gs_type1_data *pdata = &pfont->data; t1_hinter *h = &pcis->h; bool encrypted = pdata->lenIV >= 0; fixed cstack[ostack_size]; cs_ptr csp; #define clear CLEAR_CSTACK(cstack, csp) ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1]; register const byte *cip; register crypt_state state; register int c; cs_ptr ap; bool vertical; int code = 0; /****** FAKE THE REGISTRY ******/ struct { float *values; uint size; } Registry[1]; Registry[0].values = pcis->pfont->data.WeightVector.values; switch (pcis->init_done) { case -1: t1_hinter__init(h, pcis->path); break; case 0: gs_type1_finish_init(pcis); /* sets origin */ code = t1_hinter__set_mapping(h, &pcis->pis->ctm, &pfont->FontMatrix, &pfont->base->FontMatrix, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit - pcis->log2_subpixels.x, pcis->scale.y.log2_unit - pcis->log2_subpixels.y, pcis->origin.x, pcis->origin.y, gs_currentaligntopixels(pfont->dir)); if (code < 0) return code; code = t1_hinter__set_font_data(h, 2, pdata, pcis->no_grid_fitting, pcis->pfont->is_resource); if (code < 0) return code; break; default /*case 1 */ : break; } INIT_CSTACK(cstack, csp, pcis); if (pgd == 0) goto cont; ipsp->cs_data = *pgd; cip = pgd->bits.data; if (cip == 0) return (gs_note_error(gs_error_invalidfont)); call:state = crypt_charstring_seed; if (encrypted) { int skip = pdata->lenIV; /* Skip initial random bytes */ for (; skip > 0; ++cip, --skip) decrypt_skip_next(*cip, state); } goto top; cont:if (ipsp < pcis->ipstack || ipsp->ip == 0) return (gs_note_error(gs_error_invalidfont)); cip = ipsp->ip; state = ipsp->dstate; top:for (;;) { uint c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c >= c_num1) { /* This is a number, decode it and push it on the stack. */ if (c < c_pos2_0) { /* 1-byte number */ decode_push_num1(csp, cstack, c); } else if (c < cx_num4) { /* 2-byte number */ decode_push_num2(csp, cstack, c, cip, state, encrypted); } else if (c == cx_num4) { /* 4-byte number */ long lw; decode_num4(lw, cip, state, encrypted); /* 32-bit numbers are 16:16. */ CS_CHECK_PUSH(csp, cstack); *++csp = arith_rshift(lw, 16 - _fixed_shift); } else /* not possible */ return_error(gs_error_invalidfont); pushed:if_debug3('1', "[1]%d: (%d) %f\n", (int)(csp - cstack), c, fixed2float(*csp)); continue; } #ifdef DEBUG if (gs_debug['1']) { static const char *const c2names[] = {char2_command_names}; if (c2names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, c2names[c]); } #endif switch ((char_command) c) { #define cnext clear; goto top /* Commands with identical functions in Type 1 and Type 2, */ /* except for 'escape'. */ case c_undef0: case c_undef2: case c_undef17: return_error(gs_error_invalidfont); case c_callsubr: c = fixed2int_var(*csp) + pdata->subroutineNumberBias; code = pdata->procs.subr_data (pfont, c, false, &ipsp[1].cs_data); subr:if (code < 0) { /* Calling a Subr with an out-of-range index is clearly a error: * the Adobe documentation says the results of doing this are * undefined. However, we have seen a PDF file produced by Adobe * PDF Library 4.16 that included a Type 2 font that called an * out-of-range Subr, and Acrobat Reader did not signal an error. * Therefore, we ignore such calls. */ cip++; goto top; } --csp; ipsp->ip = cip, ipsp->dstate = state; ++ipsp; cip = ipsp->cs_data.bits.data; goto call; case c_return: gs_glyph_data_free(&ipsp->cs_data, "gs_type2_interpret"); --ipsp; goto cont; case c_undoc15: /* See gstype1.h for information on this opcode. */ cnext; /* Commands with similar but not identical functions */ /* in Type 1 and Type 2 charstrings. */ case cx_hstem: goto hstem; case cx_vstem: goto vstem; case cx_vmoveto: check_first_operator(csp > cstack); code = t1_hinter__rmoveto(h, 0, *csp); move: cc: if (code < 0) return code; goto pp; case cx_rlineto: for (ap = cstack; ap + 1 <= csp; ap += 2) { code = t1_hinter__rlineto(h, ap[0], ap[1]); if (code < 0) return code; } pp: cnext; case cx_hlineto: vertical = false; goto hvl; case cx_vlineto: vertical = true; hvl:for (ap = cstack; ap <= csp; vertical = !vertical, ++ap) { if (vertical) { code = t1_hinter__rlineto(h, 0, ap[0]); } else { code = t1_hinter__rlineto(h, ap[0], 0); } if (code < 0) return code; } goto pp; case cx_rrcurveto: for (ap = cstack; ap + 5 <= csp; ap += 6) { code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); if (code < 0) return code; } goto pp; case cx_endchar: /* * It is a feature of Type 2 CharStrings that if endchar is * invoked with 4 or 5 operands, it is equivalent to the * Type 1 seac operator. In this case, the asb operand of * seac is missing: we assume it is the same as the * l.s.b. of the accented character. This feature was * undocumented until the 16 March 2000 version of the Type * 2 Charstring Format specification, but, thankfully, is * described in that revision. */ if (csp >= cstack + 3) { check_first_operator(csp > cstack + 3); code = gs_type1_seac(pcis, cstack, 0, ipsp); if (code < 0) return code; clear; cip = ipsp->cs_data.bits.data; goto call; } /* * This might be the only operator in the charstring. * In this case, there might be a width on the stack. */ check_first_operator(csp >= cstack); if (pcis->seac_accent < 0) { code = t1_hinter__endglyph(h); if (code < 0) return code; code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path); if (code < 0) return code; } else { t1_hinter__setcurrentpoint(h, pcis->save_adxy.x + pcis->origin_offset.x, pcis->save_adxy.y + pcis->origin_offset.y); code = t1_hinter__end_subglyph(h); if (code < 0) return code; } code = gs_type1_endchar(pcis); if (code == 1) { /* * Reset the total hint count so that hintmask will * parse its following data correctly. * (gs_type1_endchar already reset the actual hint * tables.) */ pcis->num_hints = 0; /* do accent of seac */ ipsp = &pcis->ipstack[pcis->ips_count - 1]; cip = ipsp->cs_data.bits.data; goto call; } return code; case cx_rmoveto: /* See vmoveto above re closing the subpath. */ check_first_operator(!((csp - cstack) & 1)); if (csp > cstack + 1) { /* Some Type 2 charstrings omit the vstemhm operator before rmoveto, even though this is only allowed before hintmask and cntrmask. Thanks to Felix Pahl. */ type2_vstem(pcis, csp - 2, cstack); cstack [0] = csp [-1]; cstack [1] = csp [ 0]; csp = cstack + 1; } code = t1_hinter__rmoveto(h, csp[-1], *csp); goto move; case cx_hmoveto: /* See vmoveto above re closing the subpath. */ check_first_operator(csp > cstack); code = t1_hinter__rmoveto(h, *csp, 0); goto move; case cx_vhcurveto: vertical = true; goto hvc; case cx_hvcurveto: vertical = false; hvc:for (ap = cstack; ap + 3 <= csp; vertical = !vertical, ap += 4) { gs_fixed_point pt[2] = {{0, 0}, {0, 0}}; if (vertical) { pt[0].y = ap[0]; pt[1].x = ap[3]; if (ap + 4 == csp) pt[1].y = ap[4]; } else { pt[0].x = ap[0]; if (ap + 4 == csp) pt[1].x = ap[4]; pt[1].y = ap[3]; } code = t1_hinter__rcurveto(h, pt[0].x, pt[0].y, ap[1], ap[2], pt[1].x, pt[1].y); if (code < 0) return code; } goto pp; /*********************** * New Type 2 commands * ***********************/ case c2_blend: { int n = fixed2int_var(*csp); int num_values = csp - cstack; gs_font_type1 *pfont = pcis->pfont; int k = pfont->data.WeightVector.count; int i, j; cs_ptr base, deltas; base = csp - 1 - num_values; deltas = base + n - 1; for (j = 0; j < n; j++, base++, deltas += k - 1) for (i = 1; i < k; i++) *base += (fixed)(deltas[i] * pfont->data.WeightVector.values[i]); } cnext; case c2_hstemhm: hstem:check_first_operator(!((csp - cstack) & 1)); { fixed x = 0; for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2) { code = t1_hinter__hstem(h, x += ap[0], ap[1]); if (code < 0) return code; } } pcis->num_hints += (csp + 1 - cstack) >> 1; cnext; case c2_hintmask: /* * A hintmask at the beginning of the CharString is * equivalent to vstemhm + hintmask. For simplicity, we use * this interpretation everywhere. */ case c2_cntrmask: check_first_operator(!((csp - cstack) & 1)); type2_vstem(pcis, csp, cstack); /* * We should clear the stack here only if this is the * initial mask operator that includes the implicit * vstemhm, but currently this is too much trouble to * detect. */ clear; { byte mask[max_total_stem_hints / 8]; int i; for (i = 0; i < pcis->num_hints; ++cip, i += 8) { charstring_next(*cip, state, mask[i >> 3], encrypted); if_debug1('1', " 0x%02x", mask[i >> 3]); } if_debug0('1', "\n"); ipsp->ip = cip; ipsp->dstate = state; if (c == c2_cntrmask) { /****** NYI ******/ } else { /* hintmask or equivalent */ if_debug0('1', "[1]hstem hints:\n"); if_debug0('1', "[1]vstem hints:\n"); code = t1_hinter__hint_mask(h, mask); if (code < 0) return code; } } break; case c2_vstemhm: vstem:check_first_operator(!((csp - cstack) & 1)); type2_vstem(pcis, csp, cstack); cnext; case c2_rcurveline: for (ap = cstack; ap + 5 <= csp; ap += 6) { code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); if (code < 0) return code; } code = t1_hinter__rlineto(h, ap[0], ap[1]); goto cc; case c2_rlinecurve: for (ap = cstack; ap + 7 <= csp; ap += 2) { code = t1_hinter__rlineto(h, ap[0], ap[1]); if (code < 0) return code; } code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); goto cc; case c2_vvcurveto: ap = cstack; { int n = csp + 1 - cstack; fixed dxa = (n & 1 ? *ap++ : 0); for (; ap + 3 <= csp; ap += 4) { code = t1_hinter__rcurveto(h, dxa, ap[0], ap[1], ap[2], fixed_0, ap[3]); if (code < 0) return code; dxa = 0; } } goto pp; case c2_hhcurveto: ap = cstack; { int n = csp + 1 - cstack; fixed dya = (n & 1 ? *ap++ : 0); for (; ap + 3 <= csp; ap += 4) { code = t1_hinter__rcurveto(h, ap[0], dya, ap[1], ap[2], ap[3], fixed_0); if (code < 0) return code; dya = 0; } } goto pp; case c2_shortint: { int c1, c2; charstring_next(*cip, state, c1, encrypted); ++cip; charstring_next(*cip, state, c2, encrypted); ++cip; CS_CHECK_PUSH(csp, cstack); *++csp = int2fixed((((c1 ^ 0x80) - 0x80) << 8) + c2); } goto pushed; case c2_callgsubr: c = fixed2int_var(*csp) + pdata->gsubrNumberBias; code = pdata->procs.subr_data (pfont, c, true, &ipsp[1].cs_data); goto subr; case cx_escape: charstring_next(*cip, state, c, encrypted); ++cip; #ifdef DEBUG if (gs_debug['1'] && c < char2_extended_command_count) { static const char *const ce2names[] = {char2_extended_command_names}; if (ce2names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, ce2names[c]); } #endif switch ((char2_extended_command) c) { case ce2_and: csp[-1] = ((csp[-1] != 0) & (*csp != 0) ? fixed_1 : 0); --csp; break; case ce2_or: csp[-1] = (csp[-1] | *csp ? fixed_1 : 0); --csp; break; case ce2_not: *csp = (*csp ? 0 : fixed_1); break; case ce2_store: { int i, n = fixed2int_var(*csp); float *to = Registry[fixed2int_var(csp[-3])].values + fixed2int_var(csp[-2]); const fixed *from = pcis->transient_array + fixed2int_var(csp[-1]); for (i = 0; i < n; ++i) to[i] = fixed2float(from[i]); } csp -= 4; break; case ce2_abs: if (*csp < 0) *csp = -*csp; break; case ce2_add: csp[-1] += *csp; --csp; break; case ce2_sub: csp[-1] -= *csp; --csp; break; case ce2_div: csp[-1] = float2fixed((double)csp[-1] / *csp); --csp; break; case ce2_load: /* The specification says there is no j (starting index */ /* in registry array) argument.... */ { int i, n = fixed2int_var(*csp); const float *from = Registry[fixed2int_var(csp[-2])].values; fixed *to = pcis->transient_array + fixed2int_var(csp[-1]); for (i = 0; i < n; ++i) to[i] = float2fixed(from[i]); } csp -= 3; break; case ce2_neg: *csp = -*csp; break; case ce2_eq: csp[-1] = (csp[-1] == *csp ? fixed_1 : 0); --csp; break; case ce2_drop: --csp; break; case ce2_put: pcis->transient_array[fixed2int_var(*csp)] = csp[-1]; csp -= 2; break; case ce2_get: *csp = pcis->transient_array[fixed2int_var(*csp)]; break; case ce2_ifelse: if (csp[-1] > *csp) csp[-3] = csp[-2]; csp -= 3; break; case ce2_random: CS_CHECK_PUSH(csp, cstack); ++csp; /****** NYI ******/ break; case ce2_mul: { double prod = fixed2float(csp[-1]) * *csp; csp[-1] = (prod > max_fixed ? max_fixed : prod < min_fixed ? min_fixed : (fixed)prod); } --csp; break; case ce2_sqrt: if (*csp >= 0) *csp = float2fixed(sqrt(fixed2float(*csp))); break; case ce2_dup: CS_CHECK_PUSH(csp, cstack); csp[1] = *csp; ++csp; break; case ce2_exch: { fixed top = *csp; *csp = csp[-1], csp[-1] = top; } break; case ce2_index: *csp = (*csp < 0 ? csp[-1] : csp[-1 - fixed2int_var(csp[-1])]); break; case ce2_roll: { int distance = fixed2int_var(*csp); int count = fixed2int_var(csp[-1]); cs_ptr bot; csp -= 2; if (count < 0 || count > csp + 1 - cstack) return_error(gs_error_invalidfont); if (count == 0) break; if (distance < 0) distance = count - (-distance % count); bot = csp + 1 - count; while (--distance >= 0) { fixed top = *csp; memmove(bot + 1, bot, (count - 1) * sizeof(fixed)); *bot = top; } } break; case ce2_hflex: csp[6] = fixed_half; /* fd/100 */ csp[4] = *csp, csp[5] = 0; /* dx6, dy6 */ csp[2] = csp[-1], csp[3] = -csp[-4]; /* dx5, dy5 */ *csp = csp[-2], csp[1] = 0; /* dx4, dy4 */ csp[-2] = csp[-3], csp[-1] = 0; /* dx3, dy3 */ csp[-3] = csp[-4], csp[-4] = csp[-5]; /* dx2, dy2 */ csp[-5] = 0; /* dy1 */ csp += 6; goto flex; case ce2_flex: *csp /= 100; /* fd/100 */ flex: { fixed x_join = csp[-12] + csp[-10] + csp[-8]; fixed y_join = csp[-11] + csp[-9] + csp[-7]; fixed x_end = x_join + csp[-6] + csp[-4] + csp[-2]; fixed y_end = y_join + csp[-5] + csp[-3] + csp[-1]; gs_point join, end; double flex_depth; if ((code = gs_distance_transform(fixed2float(x_join), fixed2float(y_join), &ctm_only(pcis->pis), &join)) < 0 || (code = gs_distance_transform(fixed2float(x_end), fixed2float(y_end), &ctm_only(pcis->pis), &end)) < 0 ) return code; /* * Use the X or Y distance depending on whether * the curve is more horizontal or more * vertical. */ if (any_abs(end.y) > any_abs(end.x)) flex_depth = join.x; else flex_depth = join.y; if (fabs(flex_depth) < fixed2float(*csp)) { /* Do flex as line. */ code = t1_hinter__rlineto(h, x_end, y_end); } else { /* * Do flex as curve. We can't jump to rrc, * because the flex operators don't clear * the stack (!). */ code = t1_hinter__rcurveto(h, csp[-12], csp[-11], csp[-10], csp[-9], csp[-8], csp[-7]); if (code < 0) return code; code = t1_hinter__rcurveto(h, csp[-6], csp[-5], csp[-4], csp[-3], csp[-2], csp[-1]); } if (code < 0) return code; csp -= 13; } cnext; case ce2_hflex1: csp[4] = fixed_half; /* fd/100 */ csp[2] = *csp; /* dx6 */ csp[3] = -(csp[-7] + csp[-5] + csp[-1]); /* dy6 */ *csp = csp[-2], csp[1] = csp[-1]; /* dx5, dy5 */ csp[-2] = csp[-3], csp[-1] = 0; /* dx4, dy4 */ csp[-3] = 0; /* dy3 */ csp += 4; goto flex; case ce2_flex1: { fixed dx = csp[-10] + csp[-8] + csp[-6] + csp[-4] + csp[-2]; fixed dy = csp[-9] + csp[-7] + csp[-5] + csp[-3] + csp[-1]; if (any_abs(dx) > any_abs(dy)) csp[1] = -dy; /* d6 is dx6 */ else csp[1] = *csp, *csp = -dx; /* d6 is dy6 */ } csp[2] = fixed_half; /* fd/100 */ csp += 2; goto flex; } break; /* Fill up the dispatch up to 32. */ case_c2_undefs: default: /* pacify compiler */ return_error(gs_error_invalidfont); } } }
int gs_currentmatrix(const gs_state * pgs, gs_matrix * pmat) { *pmat = ctm_only(pgs); return 0; }