/* We implement get_params to provide a way to read out the bounding box. */ static int bbox_get_params(gx_device * dev, gs_param_list * plist) { gx_device_bbox *const bdev = (gx_device_bbox *) dev; gs_fixed_rect fbox; int code = gx_forward_get_params(dev, plist); gs_param_float_array bba; float bbox[4]; if (code < 0) return code; /* * We might be calling get_params before the device has been * initialized: in this case, box_proc_data = 0. */ if (bdev->box_proc_data == 0) fbox = bdev->bbox; else BBOX_GET_BOX(bdev, &fbox); bbox[0] = fixed2float(fbox.p.x); bbox[1] = fixed2float(fbox.p.y); bbox[2] = fixed2float(fbox.q.x); bbox[3] = fixed2float(fbox.q.y); bba.data = bbox, bba.size = 4, bba.persistent = false; code = param_write_float_array(plist, "PageBoundingBox", &bba); if (code < 0) return code; code = param_write_bool(plist, "WhiteIsOpaque", &bdev->white_is_opaque); return code; }
int gs_currentpoint(gs_state *pgs, gs_point *ppt) { gs_fixed_point pt; int code = gx_path_current_point(pgs->path, &pt); if ( code < 0 ) return code; return gs_itransform(pgs, fixed2float(pt.x), fixed2float(pt.y), ppt); }
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); }
/* May call beginpath, moveto, lineto, closepath, endpath. */ int gdev_vector_write_polygon(gx_device_vector * vdev, const gs_fixed_point * points, uint count, bool close, gx_path_type_t type) { int code = 0; if (type != gx_path_type_none && (code = (*vdev_proc(vdev, beginpath)) (vdev, type)) < 0 ) return code; if (count > 0) { double x = fixed2float(points[0].x) / vdev->scale.x, y = fixed2float(points[0].y) / vdev->scale.y; double x_start = x, y_start = y, x_prev, y_prev; uint i; code = (*vdev_proc(vdev, moveto)) (vdev, 0.0, 0.0, x, y, type); if (code >= 0) for (i = 1; i < count && code >= 0; ++i) { x_prev = x, y_prev = y; code = (*vdev_proc(vdev, lineto)) (vdev, x_prev, y_prev, (x = fixed2float(points[i].x) / vdev->scale.x), (y = fixed2float(points[i].y) / vdev->scale.y), type); } if (code >= 0 && close) code = (*vdev_proc(vdev, closepath)) (vdev, x, y, x_start, y_start, type); } return (code >= 0 && type != gx_path_type_none ? (*vdev_proc(vdev, endpath)) (vdev, type) : code); }
/* * Put a segment of an enumerated path on the output file. * pe_op is assumed to be valid and non-zero. */ int gdev_vector_dopath_segment(gdev_vector_dopath_state_t *state, int pe_op, gs_fixed_point vs[3]) { gx_device_vector *vdev = state->vdev; const gs_matrix *const pmat = &state->scale_mat; gs_point vp[3]; int code; switch (pe_op) { case gs_pe_moveto: code = gs_point_transform_inverse(fixed2float(vs[0].x), fixed2float(vs[0].y), pmat, &vp[0]); if (code < 0) return code; if (state->first) state->start = vp[0], state->first = false; code = vdev_proc(vdev, moveto) (vdev, 0/*unused*/, 0/*unused*/, vp[0].x, vp[0].y, state->type); state->prev = vp[0]; break; case gs_pe_lineto: case gs_pe_gapto: /* FIXME */ code = gs_point_transform_inverse(fixed2float(vs[0].x), fixed2float(vs[0].y), pmat, &vp[0]); if (code < 0) return code; code = vdev_proc(vdev, lineto) (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y, state->type); state->prev = vp[0]; break; case gs_pe_curveto: code = gs_point_transform_inverse(fixed2float(vs[0].x), fixed2float(vs[0].y), pmat, &vp[0]); if (code < 0) return code; code = gs_point_transform_inverse(fixed2float(vs[1].x), fixed2float(vs[1].y), pmat, &vp[1]); if (code < 0) return code; gs_point_transform_inverse(fixed2float(vs[2].x), fixed2float(vs[2].y), pmat, &vp[2]); code = vdev_proc(vdev, curveto) (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y, vp[1].x, vp[1].y, vp[2].x, vp[2].y, state->type); state->prev = vp[2]; break; case gs_pe_closepath: code = vdev_proc(vdev, closepath) (vdev, state->prev.x, state->prev.y, state->start.x, state->start.y, state->type); state->prev = state->start; break; default: /* can't happen */ return -1; } return code; }
int gs_reversepath(gs_state * pgs) { gx_path *ppath = pgs->path; gx_path rpath; int code; gx_path_init_local(&rpath, ppath->memory); code = gx_path_copy_reversed(ppath, &rpath); if (code < 0) { gx_path_free(&rpath, "gs_reversepath"); return code; } if (pgs->current_point_valid) { /* Not empty. */ gx_setcurrentpoint(pgs, fixed2float(rpath.position.x), fixed2float(rpath.position.y)); if (rpath.first_subpath != 0) { pgs->subpath_start.x = fixed2float(rpath.segments->contents.subpath_current->pt.x); pgs->subpath_start.y = fixed2float(rpath.segments->contents.subpath_current->pt.y); } } gx_path_assign_free(ppath, &rpath); return 0; }
/* Get the metrics (l.s.b. and width) from the Type 1 interpreter. */ void type1_cis_get_metrics(const gs_type1_state * pcis, double psbw[4]) { psbw[0] = fixed2float(pcis->lsb.x); psbw[1] = fixed2float(pcis->lsb.y); psbw[2] = fixed2float(pcis->width.x); psbw[3] = fixed2float(pcis->width.y); }
static void gx_print_segment(const segment * pseg) { double px = fixed2float(pseg->pt.x); double py = fixed2float(pseg->pt.y); char out[80]; sprintf(out, "0x%lx<0x%lx,0x%lx>:%u", (ulong) pseg, (ulong) pseg->prev, (ulong) pseg->next, pseg->notes); switch (pseg->type) { case s_start:{ const subpath *const psub = (const subpath *)pseg; dprintf5(" %1.4f %1.4f moveto\t%% %s #curves=%d last=0x%lx\n", px, py, out, psub->curve_count, (ulong) psub->last); break; } case s_curve:{ const curve_segment *const pcur = (const curve_segment *)pseg; dprintf7(" %1.4f %1.4f %1.4f %1.4f %1.4f %1.4f curveto\t%% %s\n", fixed2float(pcur->p1.x), fixed2float(pcur->p1.y), fixed2float(pcur->p2.x), fixed2float(pcur->p2.y), px, py, out); break; } case s_line: dprintf3(" %1.4f %1.4f lineto\t%% %s\n", px, py, out); break; case s_gap: dprintf3(" %1.4f %1.4f gapto\t%% %s\n", px, py, out); break; case s_dash:{ const dash_segment *const pd = (const dash_segment *)pseg; dprintf5(" %1.4f %1.4f %1.4f %1.4f dash\t%% %s\n", fixed2float(pd->pt.x), fixed2float(pd->pt.y), fixed2float(pd->tangent.x),fixed2float(pd->tangent.y), out); break; } case s_line_close:{ const line_close_segment *const plc = (const line_close_segment *)pseg; dprintf4(" closepath\t%% %s %1.4f %1.4f 0x%lx\n", out, px, py, (ulong) (plc->sub)); break; } default: dprintf4(" %1.4f %1.4f <type 0x%x>\t%% %s\n", px, py, pseg->type, out); } }
int gx_setcurrentpoint_from_path(gs_imager_state *pis, gx_path *path) { gs_point pt; pt.x = fixed2float(path->position.x); pt.y = fixed2float(path->position.y); gx_setcurrentpoint(pis, pt.x, pt.y); pis->current_point_valid = true; return 0; }
/* Print a matrix */ static void trace_matrix_fixed(const gs_matrix_fixed * pmat) { trace_matrix((const gs_matrix *)pmat); if (pmat->txy_fixed_valid) { dprintf2("\t\tt_fixed: [%6g %6g]\n", fixed2float(pmat->tx_fixed), fixed2float(pmat->ty_fixed)); } else { dputs("\t\tt_fixed not valid\n"); } }
/* Make a gs_matrix_fixed from a gs_matrix. */ int gs_matrix_fixed_from_matrix(gs_matrix_fixed *pfmat, const gs_matrix *pmat) { *(gs_matrix *)pfmat = *pmat; if (f_fits_in_fixed(pmat->tx) && f_fits_in_fixed(pmat->ty)) { pfmat->tx = fixed2float(pfmat->tx_fixed = float2fixed(pmat->tx)); pfmat->ty = fixed2float(pfmat->ty_fixed = float2fixed(pmat->ty)); pfmat->txy_fixed_valid = true; } else { pfmat->txy_fixed_valid = false; } return 0; }
/* Record the side bearing and character width. */ int gs_type1_sbw(gs_type1_state * pcis, fixed lsbx, fixed lsby, fixed wx, fixed wy) { if (!pcis->sb_set) pcis->lsb.x = lsbx, pcis->lsb.y = lsby, pcis->sb_set = true; /* needed for accented chars */ if (!pcis->width_set) pcis->width.x = wx, pcis->width.y = wy, pcis->width_set = true; if_debug4('1', "[1]sb=(%g,%g) w=(%g,%g)\n", fixed2float(pcis->lsb.x), fixed2float(pcis->lsb.y), fixed2float(pcis->width.x), fixed2float(pcis->width.y)); return 0; }
int main(int argc, char* argv[]) { int i; for (i = 1000; i > 0; --i) { float f1 = fixed2float(fixsqrt(int2fixed(i))); float f2 = sqrtf(i); float diff = f1 - f2; printf("%d\t%.2f\t%.2f\t%.2f\n", i, f1, f2, diff); assert(fabsf(diff) < fixed2float(2)); } TIMEIT(1000, for (i = 1000; i > 0; --i) fixsqrt(int2fixed(i))); system("pause"); return 0; }
static inline int gs_distance_transform_compat(floatp x, floatp y, const gs_matrix_fixed *m, gs_point *pt) { #if !PRECISE_CURRENTPOINT gs_fixed_point p; int code = gs_distance_transform2fixed(m, x, y, &p); if (code < 0) return code; pt->x = fixed2float(p.x); pt->y = fixed2float(p.y); return 0; #else return gs_distance_transform(x, y, (const gs_matrix *)m, pt); #endif }
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); }
/* 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; }
int gs_clippath(gs_state * pgs) { gx_path cpath; int code; gx_path_init_local(&cpath, pgs->path->memory); code = gx_cpath_to_path(pgs->clip_path, &cpath); if (code >= 0) { code = gx_path_assign_free(pgs->path, &cpath); pgs->current_point.x = fixed2float(pgs->path->position.x); pgs->current_point.y = fixed2float(pgs->path->position.y); pgs->current_point_valid = true; } if (code < 0) gx_path_free(&cpath, "gs_clippath"); return code; }
/* Read back the bounding box in 1/72" units. */ void gx_device_bbox_bbox(gx_device_bbox * dev, gs_rect * pbbox) { gs_fixed_rect bbox; BBOX_GET_BOX(dev, &bbox); if (bbox.p.x > bbox.q.x || bbox.p.y > bbox.q.y) { /* Nothing has been written on this page. */ pbbox->p.x = pbbox->p.y = pbbox->q.x = pbbox->q.y = 0; } else { gs_rect dbox; gs_matrix mat; dbox.p.x = fixed2float(bbox.p.x); dbox.p.y = fixed2float(bbox.p.y); dbox.q.x = fixed2float(bbox.q.x); dbox.q.y = fixed2float(bbox.q.y); gs_deviceinitialmatrix((gx_device *)dev, &mat); gs_bbox_transform_inverse(&dbox, &mat, pbbox); } }
/* otherwise, return the element type. */ int gs_path_enum_next(gs_path_enum * penum, gs_point ppts[3]) { gs_fixed_point fpts[3]; int pe_op = gx_path_enum_next(penum, fpts); int code; switch (pe_op) { case 0: /* all done */ case gs_pe_closepath: break; case gs_pe_curveto: if ((code = gs_point_transform_inverse( fixed2float(fpts[1].x), fixed2float(fpts[1].y), &penum->mat, &ppts[1])) < 0 || (code = gs_point_transform_inverse( fixed2float(fpts[2].x), fixed2float(fpts[2].y), &penum->mat, &ppts[2])) < 0) return code; /* falls through */ case gs_pe_moveto: case gs_pe_lineto: if ((code = gs_point_transform_inverse( fixed2float(fpts[0].x), fixed2float(fpts[0].y), &penum->mat, &ppts[0])) < 0) return code; default: /* error */ break; } return pe_op; }
/* Print a path */ void gx_path_print(const gx_path * ppath) { const segment *pseg = (const segment *)ppath->first_subpath; dmlprintf5(ppath->memory, " %% state_flags=%d subpaths=%d, curves=%d, point=(%f,%f)\n", ppath->state_flags, ppath->subpath_count, ppath->curve_count, fixed2float(ppath->position.x), fixed2float(ppath->position.y)); dmlprintf5(ppath->memory," %% box=(%f,%f),(%f,%f) last=0x%lx\n", fixed2float(ppath->bbox.p.x), fixed2float(ppath->bbox.p.y), fixed2float(ppath->bbox.q.x), fixed2float(ppath->bbox.q.y), (ulong) ppath->box_last); dmlprintf4(ppath->memory, " %% segments=0x%lx (refct=%ld, first=0x%lx, current=0x%lx)\n", (ulong) ppath->segments, (long)ppath->segments->rc.ref_count, (ulong) ppath->segments->contents.subpath_first, (ulong) ppath->segments->contents.subpath_current); while (pseg) { dmlputs(ppath->memory,""); gx_print_segment(ppath->memory, pseg); pseg = pseg->next; } }
static int svg_dorect(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1, fixed y1, gx_path_type_t type) { gx_device_svg *svg = (gx_device_svg *)vdev; char line[300]; /* hack single-page output */ if (svg->page_count) return 0; dprintf("svg_dorect "); svg_print_path_type(svg, type); dprintf("\n"); svg_write_state(svg); if (type & gx_path_type_clip) { svg_write(svg, "<clipPath>\n"); } sprintf(line, "<rect x='%lf' y='%lf' width='%lf' height='%lf'", fixed2float(x0), fixed2float(y0), fixed2float(x1 - x0), fixed2float(y1 - y0)); svg_write(svg, line); /* override the inherited stroke attribute if we're not stroking */ if (!(type & gx_path_type_stroke) && svg->strokecolor) svg_write(svg, " stroke='none'"); /* override the inherited fill attribute if we're not filling */ if (!(type & gx_path_type_fill) && svg->fillcolor) svg_write(svg, " fill='none'"); svg_write(svg, "/>\n"); if (type & gx_path_type_clip) { svg_write(svg, "</clipPath>\n"); } return 0; }
void pcl_mark_page_for_current_pos(pcl_state_t *pcs) { /* nothing to do */ if ( pcs->page_marked ) return; /* convert current point to device space and check if it is inside device rectangle for the page */ { gs_fixed_rect page_bbox_fixed = pcs->xfm_state.dev_print_rect; gs_rect page_bbox_float; gs_point current_pt, dev_pt; page_bbox_float.p.x = fixed2float(page_bbox_fixed.p.x); page_bbox_float.p.y = fixed2float(page_bbox_fixed.p.y); page_bbox_float.q.x = fixed2float(page_bbox_fixed.q.x); page_bbox_float.q.y = fixed2float(page_bbox_fixed.q.y); if ( gs_currentpoint(pcs->pgs, ¤t_pt) < 0 ) { dprintf("Not expected to fail\n" ); return; } if ( gs_transform(pcs->pgs, current_pt.x, current_pt.y, &dev_pt) ) { dprintf("Not expected to fail\n" ); return; } /* half-open lower - not sure this is correct */ if ( dev_pt.x >= page_bbox_float.p.x && dev_pt.y >= page_bbox_float.p.y && dev_pt.x < page_bbox_float.q.x && dev_pt.y < page_bbox_float.q.y ) pcs->page_marked = true; } }
/* Compute the stroked outline of the current path */ int gs_strokepath(gs_state * pgs) { gx_path spath; int code; gx_path_init_local(&spath, pgs->path->memory); code = gx_stroke_add(pgs->path, &spath, pgs); if (code < 0) { gx_path_free(&spath, "gs_strokepath"); return code; } pgs->device->sgr.stroke_stored = false; code = gx_path_assign_free(pgs->path, &spath); if (code < 0) return code; /* NB: needs testing with PCL */ if (CPSI_mode && gx_path_is_void(pgs->path)) pgs->current_point_valid = false; else gx_setcurrentpoint(pgs, fixed2float(spath.position.x), fixed2float(spath.position.y)); return 0; }
/* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */ int gx_translate_to_fixed(register gs_state * pgs, fixed px, fixed py) { double fpx = fixed2float(px); double fdx = fpx - pgs->ctm.tx; double fpy = fixed2float(py); double fdy = fpy - pgs->ctm.ty; fixed dx, dy; int code; if (pgs->ctm.txy_fixed_valid) { dx = float2fixed(fdx); dy = float2fixed(fdy); code = gx_path_translate(pgs->path, dx, dy); if (code < 0) return code; if (pgs->char_tm_valid && pgs->char_tm.txy_fixed_valid) pgs->char_tm.tx_fixed += dx, pgs->char_tm.ty_fixed += dy; } else { if (!gx_path_is_null(pgs->path)) return_error(gs_error_limitcheck); } pgs->ctm.tx = fpx; pgs->ctm.tx_fixed = px; pgs->ctm.ty = fpy; pgs->ctm.ty_fixed = py; pgs->ctm.txy_fixed_valid = true; pgs->ctm_inverse_valid = false; if (pgs->char_tm_valid) { /* Update char_tm now, leaving it valid. */ pgs->char_tm.tx += fdx; pgs->char_tm.ty += fdy; } #ifdef DEBUG if (gs_debug_c('x')) { dlprintf2("[x]translate_to_fixed %g, %g:\n", fixed2float(px), fixed2float(py)); trace_ctm(pgs); dlprintf("[x] char_tm:\n"); trace_matrix_fixed(&pgs->char_tm); } #endif gx_setcurrentpoint(pgs, fixed2float(pgs->ctm.tx_fixed), fixed2float(pgs->ctm.ty_fixed)); pgs->current_point_valid = true; return 0; }
int gs_type1_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat, int members, gs_glyph_info_t *info) { gs_font_type1 *const pfont = (gs_font_type1 *)font; gs_type1_data *const pdata = &pfont->data; int wmode = ((members & GLYPH_INFO_WIDTH1) != 0); int piece_members = members & (GLYPH_INFO_NUM_PIECES | GLYPH_INFO_PIECES); int width_members = (members & ((GLYPH_INFO_WIDTH0 << wmode) | (GLYPH_INFO_VVECTOR0 << wmode))); int default_members = members & ~(piece_members | GLYPH_INFO_WIDTHS | GLYPH_INFO_VVECTOR0 | GLYPH_INFO_VVECTOR1 | GLYPH_INFO_OUTLINE_WIDTHS); int code = 0; gs_glyph_data_t gdata; if (default_members) { code = gs_default_glyph_info(font, glyph, pmat, default_members, info); if (code < 0) return code; } else info->members = 0; if (default_members == members) return code; /* all done */ gdata.memory = pfont->memory; if ((code = pdata->procs.glyph_data(pfont, glyph, &gdata)) < 0) return code; /* non-existent glyph */ if (piece_members) { code = gs_type1_glyph_pieces(pfont, &gdata, members, info); if (code < 0) return code; info->members |= piece_members; } if (width_members) { gx_path path; /* * Interpret the CharString until we get to the [h]sbw. */ gs_imager_state gis; gs_type1_state cis; int value; /* Initialize just enough of the imager state. */ if (pmat) gs_matrix_fixed_from_matrix(&gis.ctm, pmat); else { gs_matrix imat; gs_make_identity(&imat); gs_matrix_fixed_from_matrix(&gis.ctm, &imat); } gis.flatness = 0; code = gs_type1_interp_init(&cis, &gis, NULL /* no path needed */, NULL, NULL, true, 0, pfont); if (code < 0) return code; cis.no_grid_fitting = true; gx_path_init_bbox_accumulator(&path); cis.path = &path; code = pdata->interpret(&cis, &gdata, &value); switch (code) { case 0: /* done with no [h]sbw, error */ /* Adobe interpreters ignore the error! */ info->width[wmode].x = 0; info->width[wmode].y = 0; info->v.x = 0; info->v.y = 0; break; default: /* code < 0, error */ return code; case type1_result_callothersubr: /* unknown OtherSubr */ return_error(gs_error_rangecheck); /* can't handle it */ case type1_result_sbw: info->width[wmode].x = fixed2float(cis.width.x); info->width[wmode].y = fixed2float(cis.width.y); info->v.x = fixed2float(cis.lsb.x); info->v.y = fixed2float(cis.lsb.y); break; } info->members |= width_members | (GLYPH_INFO_VVECTOR0 << wmode); } gs_glyph_data_free(&gdata, "gs_type1_glyph_info"); return code; }
irender_proc_t gs_image_class_1_simple(gx_image_enum * penum) { irender_proc_t rproc; fixed ox = dda_current(penum->dda.pixel0.x); fixed oy = dda_current(penum->dda.pixel0.y); if (penum->use_rop || penum->spp != 1 || penum->bps != 1) return 0; switch (penum->posture) { case image_portrait: { /* Use fast portrait algorithm. */ long dev_width = fixed2long_pixround(ox + penum->x_extent.x) - fixed2long_pixround(ox); if (dev_width != penum->rect.w) { /* * Add an extra align_bitmap_mod of padding so that * we can align scaled rows with the device. */ long line_size = bitmap_raster(any_abs(dev_width)) + align_bitmap_mod; if (penum->adjust != 0 || line_size > max_uint) return 0; /* Must buffer a scan line. */ penum->line_width = any_abs(dev_width); penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *)penum, false); return 0; } } if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n", penum->rect.w, dev_width); rproc = image_render_simple; break; } case image_landscape: { /* Use fast landscape algorithm. */ long dev_width = fixed2long_pixround(oy + penum->x_extent.y) - fixed2long_pixround(oy); long line_size = (dev_width = any_abs(dev_width), bitmap_raster(dev_width) * 8 + ROUND_UP(dev_width, 8) * align_bitmap_mod); if ((dev_width != penum->rect.w && penum->adjust != 0) || line_size > max_uint ) return 0; /* Must buffer a group of 8N scan lines. */ penum->line_width = dev_width; penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *) penum, false); return 0; } penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox); if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n", penum->rect.w, dev_width, line_size); rproc = image_render_landscape; /* Precompute values needed for rasterizing. */ penum->dxy = float2fixed(penum->matrix.xy + fixed2float(fixed_epsilon) / 2); break; } default: return 0; } /* Precompute values needed for rasterizing. */ penum->dxx = float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2); /* * We don't want to spread the samples, but we have to reset unpack_bps * to prevent the buffer pointer from being incremented by 8 bytes per * input byte. */ penum->unpack = sample_unpack_copy; penum->unpack_bps = 8; if (penum->use_mask_color) { /* * Set the masked color as 'no_color' to make it transparent * according to the mask color range and the decoding. */ penum->masked = true; if (penum->mask_color.values[0] == 1) { /* if v0 == 1, 1 is transparent since v1 must be == 1 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor0 : penum->icolor1, gx_no_color_index); } else if (penum->mask_color.values[1] == 0) { /* if v1 == 0, 0 is transparent since v0 must be == 0 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor1 : penum->icolor0, gx_no_color_index); } else { /* * The only other possible in-range value is v0 = 0, v1 = 1. * The image is completely transparent! */ rproc = image_render_skip; } penum->map[0].decoding = sd_none; } return rproc; }
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 gslt_outline_font_glyph(gs_state *pgs, gslt_font_t *xf, int gid, gslt_outline_walker_t *walk) { gs_text_params_t params; gs_text_enum_t *textenum; gs_matrix matrix; segment *seg; curve_segment *cseg; gs_gsave(pgs); gs_make_identity(&matrix); gs_setmatrix(pgs, &matrix); gs_scale(pgs, 1000.0, 1000.0); /* otherwise we hit serious precision problems with fixpoint math */ /* set gstate params */ gs_setfont(pgs, xf->font); /* set pgs->font and invalidate existing charmatrix */ gs_make_identity(&matrix); gs_setcharmatrix(pgs, &matrix); /* set the charmatrix to identity */ /* reset the path */ gs_newpath(pgs); gs_moveto(pgs, 0.0, 0.0); /* draw the glyph, in charpath mode */ params.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_DO_FALSE_CHARPATH | TEXT_RETURN_WIDTH; params.data.d_glyph = gid; params.size = 1; if (gs_text_begin(pgs, ¶ms, xf->font->memory, &textenum) != 0) return gs_throw(-1, "cannot gs_text_begin()"); if (gs_text_process(textenum) != 0) return gs_throw(-1, "cannot gs_text_process()"); gs_text_release(textenum, "gslt font outline"); /* walk the resulting path */ seg = (segment*)pgs->path->first_subpath; while (seg) { switch (seg->type) { case s_start: walk->moveto(walk->user, fixed2float(seg->pt.x) * 0.001, fixed2float(seg->pt.y) * 0.001); break; case s_line: walk->lineto(walk->user, fixed2float(seg->pt.x) * 0.001, fixed2float(seg->pt.y) * 0.001); break; case s_line_close: walk->closepath(walk->user); break; case s_curve: cseg = (curve_segment*)seg; walk->curveto(walk->user, fixed2float(cseg->p1.x) * 0.001, fixed2float(cseg->p1.y) * 0.001, fixed2float(cseg->p2.x) * 0.001, fixed2float(cseg->p2.y) * 0.001, fixed2float(seg->pt.x) * 0.001, fixed2float(seg->pt.y) * 0.001); break; } seg = seg->next; } /* and toss it away... */ gs_newpath(pgs); gs_grestore(pgs); return 0; }
static int subpath_expand_dashes(const subpath * psub, gx_path * ppath, const gs_imager_state * pis, const gx_dash_params * dash) { const float *pattern = dash->pattern; int count, index; bool ink_on; double elt_length; fixed x0 = psub->pt.x, y0 = psub->pt.y; fixed x, y; const segment *pseg; int wrap = (dash->init_ink_on && psub->is_closed ? -1 : 0); int drawing = wrap; segment_notes notes = ~sn_not_first; const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis); bool zero_length = true; int code; if ((code = gx_path_add_point(ppath, x0, y0)) < 0) return code; /* * To do the right thing at the beginning of a closed path, we have * to skip any initial line, and then redo it at the end of the * path. Drawing = -1 while skipping, 0 while drawing normally, and * 1 on the second round. Note that drawing != 0 implies ink_on. */ top:count = dash->pattern_size; ink_on = dash->init_ink_on; index = dash->init_index; elt_length = dash->init_dist_left; x = x0, y = y0; pseg = (const segment *)psub; while ((pseg = pseg->next) != 0 && pseg->type != s_start) { fixed sx = pseg->pt.x, sy = pseg->pt.y; fixed udx = sx - x, udy = sy - y; double length, dx, dy; double scale = 1; double left; if (!(udx | udy)) { /* degenerate */ if (pgs_lp->dot_length == 0 && pgs_lp->cap != gs_cap_round) { /* From PLRM, stroke operator : If a subpath is degenerate (consists of a single-point closed path or of two or more points at the same coordinates), stroke paints it only if round line caps have been specified */ if (zero_length || pseg->type != s_line_close) continue; } dx = 0, dy = 0, length = 0; } else { gs_point d; zero_length = false; dx = udx, dy = udy; /* scaled as fixed */ gs_imager_idtransform(pis, dx, dy, &d); length = hypot(d.x, d.y) * (1.0 / fixed_1); if (gs_imager_currentdashadapt(pis)) { double reps = length / dash->pattern_length; scale = reps / ceil(reps); /* Ensure we're starting at the start of a */ /* repetition. (This shouldn't be necessary, */ /* but it is.) */ count = dash->pattern_size; ink_on = dash->init_ink_on; index = dash->init_index; elt_length = dash->init_dist_left * scale; } } left = length; while (left > elt_length) { /* We are using up the line segment. */ double fraction = elt_length / length; fixed fx = (fixed) (dx * fraction); fixed fy = (fixed) (dy * fraction); fixed nx = x + fx; fixed ny = y + fy; if (ink_on) { if (drawing >= 0) { if (left >= elt_length && any_abs(fx) + any_abs(fy) < fixed_half) code = gx_path_add_dash_notes(ppath, nx, ny, udx, udy, notes & pseg->notes); else code = gx_path_add_line_notes(ppath, nx, ny, notes & pseg->notes); } notes |= sn_not_first; } else { if (drawing > 0) /* done */ return 0; code = gx_path_add_point(ppath, nx, ny); notes &= ~sn_not_first; drawing = 0; } if (code < 0) return code; left -= elt_length; ink_on = !ink_on; if (++index == count) index = 0; elt_length = pattern[index] * scale; x = nx, y = ny; } elt_length -= left; /* Handle the last dash of a segment. */ on:if (ink_on) { if (drawing >= 0) { if (pseg->type == s_line_close && drawing > 0) code = gx_path_close_subpath_notes(ppath, notes & pseg->notes); else if (any_abs(sx - x) + any_abs(sy - y) < fixed_half) code = gx_path_add_dash_notes(ppath, sx, sy, udx, udy, notes & pseg->notes); else code = gx_path_add_line_notes(ppath, sx, sy, notes & pseg->notes); notes |= sn_not_first; } } else { code = gx_path_add_point(ppath, sx, sy); notes &= ~sn_not_first; if (elt_length < fixed2float(fixed_epsilon) && (pseg->next == 0 || pseg->next->type == s_start || elt_length == 0)) { /* * Ink is off, but we're within epsilon of the end * of the dash element. * "Stretch" a little so we get a dot. * Also if the next dash pattern is zero length, * use the last segment orientation. */ double elt_length1; if (code < 0) return code; if (++index == count) index = 0; elt_length1 = pattern[index] * scale; if (pseg->next == 0 || pseg->next->type == s_start) { elt_length = elt_length1; left = 0; ink_on = true; goto on; } /* Looking ahead one dash pattern element. If it is zero length, apply to the current segment (at its end). */ if (elt_length1 == 0) { left = 0; code = gx_path_add_dash_notes(ppath, sx, sy, udx, udy, notes & pseg->notes); if (++index == count) index = 0; elt_length = pattern[index] * scale; ink_on = false; } else if (--index == 0) { /* Revert lookahead. */ index = count - 1; } } if (drawing > 0) /* done */ return code; drawing = 0; } if (code < 0) return code; x = sx, y = sy; } /* Check for wraparound. */ if (wrap && drawing <= 0) { /* We skipped some initial lines. */ /* Go back and do them now. */ drawing = 1; goto top; } return 0; }
/* this procedure is exported for the benefit of gsicc.c */ int gx_cie_real_remap_finish(cie_cached_vector3 vec3, frac * pconc, const gs_imager_state * pis, const gs_color_space *pcs) { const gs_cie_render *pcrd = pis->cie_render; const gx_cie_joint_caches *pjc = pis->cie_joint_caches; const gs_const_string *table = pcrd->RenderTable.lookup.table; int tabc[3]; /* indices for final EncodeABC lookup */ /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */ if (!pjc->skipDecodeLMN) cie_lookup_map3(&vec3 /* LMN => PQR */, &pjc->DecodeLMN, "Decode/MatrixLMN+MatrixPQR"); /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */ if (!pjc->skipPQR) cie_lookup_map3(&vec3 /* PQR => LMN */, &pjc->TransformPQR, "Transform/Matrix'PQR+MatrixLMN"); /* Apply EncodeLMN and MatrixABC(encode). */ if (!pjc->skipEncodeLMN) cie_lookup_map3(&vec3 /* LMN => ABC */, &pcrd->caches.EncodeLMN, "EncodeLMN+MatrixABC"); /* MatrixABCEncode includes the scaling of the EncodeABC */ /* cache index. */ #define SET_TABC(i, t)\ BEGIN\ tabc[i] = cie_cached2int(vec3 /*ABC*/.t - pcrd->EncodeABC_base[i],\ _cie_interpolate_bits);\ if ((uint)tabc[i] > (gx_cie_cache_size - 1) << _cie_interpolate_bits)\ tabc[i] = (tabc[i] < 0 ? 0 :\ (gx_cie_cache_size - 1) << _cie_interpolate_bits);\ END SET_TABC(0, u); SET_TABC(1, v); SET_TABC(2, w); #undef SET_TABC if (table == 0) { /* * No further transformation. * The final mapping step includes both restriction to * the range [0..1] and conversion to fracs. */ #define EABC(i)\ cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.fracs.values, tabc[i]) pconc[0] = EABC(0); pconc[1] = EABC(1); pconc[2] = EABC(2); #undef EABC return 3; } else { /* * Use the RenderTable. */ int m = pcrd->RenderTable.lookup.m; #define RT_LOOKUP(j, i) pcrd->caches.RenderTableT[j].fracs.values[i] #ifdef CIE_RENDER_TABLE_INTERPOLATE /* * The final mapping step includes restriction to the * ranges [0..dims[c]] as ints with interpolation bits. */ fixed rfix[3]; const int s = _fixed_shift - _cie_interpolate_bits; #define EABC(i)\ cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.ints.values, tabc[i]) #define FABC(i, s)\ ((s) > 0) ? (EABC(i) << (s)) : (EABC(i) >> -(s)) rfix[0] = FABC(0, s); rfix[1] = FABC(1, s); rfix[2] = FABC(2, s); #undef FABC #undef EABC if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n", cie_cached2float(vec3.u), cie_cached2float(vec3.v), cie_cached2float(vec3.w), fixed2float(rfix[0]), fixed2float(rfix[1]), fixed2float(rfix[2])); gx_color_interpolate_linear(rfix, &pcrd->RenderTable.lookup, pconc); if_debug3('c', "[c] interpolated => %g,%g,%g\n", frac2float(pconc[0]), frac2float(pconc[1]), frac2float(pconc[2])); if (!pcrd->caches.RenderTableT_is_identity) { /* Map the interpolated values. */ #define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size) pconc[0] = RT_LOOKUP(0, frac2cache_index(pconc[0])); pconc[1] = RT_LOOKUP(1, frac2cache_index(pconc[1])); pconc[2] = RT_LOOKUP(2, frac2cache_index(pconc[2])); if (m > 3) pconc[3] = RT_LOOKUP(3, frac2cache_index(pconc[3])); #undef frac2cache_index } #else /* !CIE_RENDER_TABLE_INTERPOLATE */ /* * The final mapping step includes restriction to the ranges * [0..dims[c]], plus scaling of the indices in the strings. */ #define RI(i)\ pcrd->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits] int ia = RI(0); int ib = RI(1); /* pre-multiplied by m * NC */ int ic = RI(2); /* pre-multiplied by m */ const byte *prtc = table[ia].data + ib + ic; /* (*pcrd->RenderTable.T)(prtc, m, pcrd, pconc); */ if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n", cie_cached2float(vec3.u), cie_cached2float(vec3.v), cie_cached2float(vec3.w), ia, ib, ic); if (pcrd->caches.RenderTableT_is_identity) { pconc[0] = byte2frac(prtc[0]); pconc[1] = byte2frac(prtc[1]); pconc[2] = byte2frac(prtc[2]); if (m > 3) pconc[3] = byte2frac(prtc[3]); } else { #if gx_cie_log2_cache_size == 8 # define byte2cache_index(b) (b) #else # if gx_cie_log2_cache_size > 8 # define byte2cache_index(b)\ ( ((b) << (gx_cie_log2_cache_size - 8)) +\ ((b) >> (16 - gx_cie_log2_cache_size)) ) # else /* < 8 */ # define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size)) # endif #endif pconc[0] = RT_LOOKUP(0, byte2cache_index(prtc[0])); pconc[1] = RT_LOOKUP(1, byte2cache_index(prtc[1])); pconc[2] = RT_LOOKUP(2, byte2cache_index(prtc[2])); if (m > 3) pconc[3] = RT_LOOKUP(3, byte2cache_index(prtc[3])); #undef byte2cache_index } #endif /* !CIE_RENDER_TABLE_INTERPOLATE */ #undef RI #undef RT_LOOKUP return m; } }