/* <userpath> <matrix> ustrokepath - */ static int zustrokepath(i_ctx_t *i_ctx_p) { gx_path save; gs_matrix saved_matrix; int npop, code = gs_currentmatrix(igs, &saved_matrix); if (code < 0) return code; /* Save and reset the path. */ gx_path_init_local(&save, imemory); gx_path_assign_preserve(&save, igs->path); if ((code = npop = upath_stroke(i_ctx_p, NULL, false)) < 0 || (code = gs_strokepath(igs)) < 0 ) { gx_path_assign_free(igs->path, &save); return code; } /* * If a matrix was specified then restore the previous matrix. */ if (npop > 1) { if ((code = gs_setmatrix(igs, &saved_matrix)) < 0) { gx_path_assign_free(igs->path, &save); return code; } } gx_path_free(&save, "ustrokepath"); pop(npop); return 0; }
static int hpgl_picture_frame_coords(hpgl_state_t *pgls, gs_int_rect *gl2_win) { gs_rect dev_win; /* device window */ hpgl_real_t x1 = pgls->g.picture_frame.anchor_point.x; hpgl_real_t y1 = pgls->g.picture_frame.anchor_point.y; hpgl_real_t x2 = x1 + pgls->g.picture_frame_width; hpgl_real_t y2 = y1 + pgls->g.picture_frame_height; pcl_set_ctm(pgls, false); hpgl_call(gs_transform(pgls->pgs, x1, y1, &dev_win.p)); hpgl_call(gs_transform(pgls->pgs, x2, y2, &dev_win.q)); hpgl_call(hpgl_set_plu_ctm(pgls)); /* * gs_bbox_transform_inverse puts the resulting points in the * correct order, with p < q. */ { gs_matrix mat; gs_rect pcl_win; /* pcl window */ gs_currentmatrix(pgls->pgs, &mat); hpgl_call(gs_bbox_transform_inverse(&dev_win, &mat, &pcl_win)); /* Round all coordinates to the nearest integer. */ #define set_round(e) gl2_win->e = (int)floor(pcl_win.e + 0.5) set_round(p.x); set_round(p.y); set_round(q.x); set_round(q.y); #undef set_round } /* restore the ctm */ hpgl_call(hpgl_set_ctm(pgls)); return 0; }
/* Start enumerating a path */ int gs_path_enum_copy_init(gs_path_enum * penum, const gs_state * pgs, bool copy) { gs_memory_t *mem = pgs->memory; if (copy) { gx_path *copied_path = gx_path_alloc(mem, "gs_path_enum_init"); int code; if (copied_path == 0) return_error(gs_error_VMerror); code = gx_path_copy(pgs->path, copied_path); if (code < 0) { gx_path_free(copied_path, "gs_path_enum_init"); return code; } gx_path_enum_init(penum, copied_path); penum->copied_path = copied_path; } else { gx_path_enum_init(penum, pgs->path); } penum->memory = mem; gs_currentmatrix(pgs, &penum->mat); return 0; }
static int zsizeimagebox(i_ctx_t *i_ctx_p) { os_ptr op = osp; const gx_device *dev = gs_currentdevice(igs); gs_rect srect, drect; gs_matrix mat; gs_int_rect rect; int w, h; int code; check_type(op[-4], t_integer); check_type(op[-3], t_integer); check_type(op[-2], t_integer); check_type(op[-1], t_integer); srect.p.x = op[-4].value.intval; srect.p.y = op[-3].value.intval; srect.q.x = srect.p.x + op[-2].value.intval; srect.q.y = srect.p.y + op[-1].value.intval; gs_currentmatrix(igs, &mat); gs_bbox_transform(&srect, &mat, &drect); /* * We want the dimensions of the image as a source, not a * destination, so we need to expand it rather than pixround. */ rect.p.x = (int)floor(drect.p.x); rect.p.y = (int)floor(drect.p.y); rect.q.x = (int)ceil(drect.q.x); rect.q.y = (int)ceil(drect.q.y); /* * Clip the rectangle to the device boundaries, since that's what * the NeXT implementation does. */ box_confine(&rect.p.x, &rect.q.x, dev->width); box_confine(&rect.p.y, &rect.q.y, dev->height); w = rect.q.x - rect.p.x; h = rect.q.y - rect.p.y; /* * The NeXT documentation doesn't specify very clearly what is * supposed to be in the matrix: the following produces results * that match testing on an actual NeXT system. */ mat.tx -= rect.p.x; mat.ty -= rect.p.y; code = write_matrix(op, &mat); if (code < 0) return code; make_int(op - 4, rect.p.x); make_int(op - 3, rect.p.y); make_int(op - 2, w); make_int(op - 1, h); return 0; }
/* Common code for composite and dissolve. */ static int composite_image(i_ctx_t *i_ctx_p, const gs_composite_alpha_params_t * params) { os_ptr op = osp; alpha_composite_state_t cstate; gs_image2_t image; double src_rect[4]; double dest_pt[2]; gs_matrix save_ctm; int code = xywh_param(op - 4, src_rect); cstate.params = *params; gs_image2_t_init(&image); if (code < 0 || (code = num_params(op - 1, 2, dest_pt)) < 0 ) return code; if (r_has_type(op - 3, t_null)) image.DataSource = igs; else { check_stype(op[-3], st_igstate_obj); check_read(op[-3]); image.DataSource = igstate_ptr(op - 3); } image.XOrigin = src_rect[0]; image.YOrigin = src_rect[1]; image.Width = src_rect[2]; image.Height = src_rect[3]; image.PixelCopy = true; /* Compute appropriate transformations. */ gs_currentmatrix(igs, &save_ctm); gs_translate(igs, dest_pt[0], dest_pt[1]); gs_make_identity(&image.ImageMatrix); if (image.DataSource == igs) { image.XOrigin -= dest_pt[0]; image.YOrigin -= dest_pt[1]; } code = begin_composite(i_ctx_p, &cstate); if (code >= 0) { code = process_non_source_image(i_ctx_p, (const gs_image_common_t *)&image, "composite_image"); end_composite(i_ctx_p, &cstate); if (code >= 0) pop(8); } gs_setmatrix(igs, &save_ctm); return code; }
/* - .currentmatrix <xx> <xy> <yx> <yy> <tx> <ty> */ static int zcurrentmatrix(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_matrix mat; int code = gs_currentmatrix(igs, &mat); if (code < 0) return code; push(6); code = make_floats(op - 5, &mat.xx, 6); if (code < 0) pop(6); return code; }
static int pl_fapi_build_char(gs_show_enum * penum, gs_state * pgs, gs_font * pfont, gs_char chr, gs_glyph glyph) { int code; gs_matrix save_ctm; gs_font_base *pbfont = (gs_font_base *) pfont; pl_font_t *plfont = (pl_font_t *) pfont->client_data; gs_fapi_server *I = pbfont->FAPI; I->ff.embolden = plfont->bold_fraction; I->ff.is_mtx_skipped = plfont->is_xl_format; code = gs_fapi_do_char(pfont, pgs, (gs_text_enum_t *) penum, NULL, false, NULL, NULL, chr, glyph, 0); if (code == gs_error_unknownerror) { gs_fapi_font tmp_ff; tmp_ff.fapi_set_cache = I->ff.fapi_set_cache; /* save the ctm */ gs_currentmatrix(pgs, &save_ctm); /* magic numbers - we don't completelely understand the translation magic used by HP. This provides a good approximation */ gs_translate(pgs, 1.0 / 1.15, -(1.0 - 1.0 / 1.15)); gs_rotate(pgs, 90); I->ff.fapi_set_cache = pl_fapi_set_cache_rotate; code = gs_fapi_do_char(pfont, pgs, (gs_text_enum_t *) penum, NULL, false, NULL, NULL, chr, glyph, 0); I->ff.fapi_set_cache = tmp_ff.fapi_set_cache; gs_setmatrix(pgs, &save_ctm); } I->ff.embolden = 0; return (code); }
/* Add a symbol to the path. */ static int hpgl_stick_arc_build_char(gs_show_enum *penum, gs_state *pgs, gs_font *pfont, gs_glyph uni_code, hpgl_font_type_t font_type) { int width; gs_matrix save_ctm; int code; /* we assert the font is present at this point */ width = hpgl_stick_arc_width(uni_code, font_type); /* *** incorrect comment The TRM says the stick font is based on a 32x32 unit cell, */ /* but the font we're using here is only 15x15. */ /* Also, per TRM 23-18, the character cell is only 2/3 the */ /* point size. */ gs_setcharwidth(penum, pgs, width / 1024.0 * 0.667, 0.0); gs_currentmatrix(pgs, &save_ctm); gs_scale(pgs, 1.0 / 1024.0 * .667, 1.0 / 1024.0 * .667); gs_moveto(pgs, 0.0, 0.0); code = hpgl_stick_arc_segments(pfont->memory, (void *)pgs, uni_code, font_type); if ( code < 0 ) return code; gs_setdefaultmatrix(pgs, NULL); gs_initmatrix(pgs); /* Set predictable join and cap styles. */ gs_setlinejoin(pgs, gs_join_round); gs_setmiterlimit(pgs, 2.61); /* start beveling at 45 degrees */ gs_setlinecap(pgs, gs_cap_round); { float pattern[1]; gs_setdash(pgs, pattern, 0, 0); } gs_stroke(pgs); gs_setmatrix(pgs, &save_ctm); return 0; }
/* * Reset all parameters which must be reset whenever the page size changes. * * The third operand indicates if this routine is being called as part of * an initial reset. In that case, done't call HPGL's reset - the reset * will do that later. */ static void new_page_size( pcl_state_t * pcs, const pcl_paper_size_t * psize, bool reset_initial, bool for_passthrough ) { floatp width_pts = psize->width * 0.01; floatp height_pts = psize->height * 0.01; float page_size[2]; static float old_page_size[2] = { 0, 0 }; gs_state * pgs = pcs->pgs; gs_matrix mat; bool changed_page_size; page_size[0] = width_pts; page_size[1] = height_pts; old_page_size[0] = pcs->xfm_state.paper_size ? pcs->xfm_state.paper_size->width : 0; old_page_size[1] = pcs->xfm_state.paper_size ? pcs->xfm_state.paper_size->height : 0; put_param1_float_array(pcs, "PageSize", page_size); /* * Reset the default transformation. * * The graphic library provides a coordinate system in points, with the * origin at the lower left corner of the page. The PCL code uses a * coordinate system in centi-points, with the origin at the upper left * corner of the page. */ gs_setdefaultmatrix(pgs, NULL); gs_initmatrix(pgs); gs_currentmatrix(pgs, &mat); gs_matrix_translate(&mat, 0.0, height_pts, &mat); gs_matrix_scale(&mat, 0.01, -0.01, &mat); gs_setdefaultmatrix(pgs, &mat); pcs->xfm_state.paper_size = psize; pcs->overlay_enabled = false; update_xfm_state(pcs, reset_initial); reset_margins(pcs, for_passthrough); /* check if update_xfm_state changed the page size */ changed_page_size = !(old_page_size[0] == pcs->xfm_state.paper_size->width && old_page_size[1] == pcs->xfm_state.paper_size->height); /* * make sure underlining is disabled (homing the cursor may cause * an underline to be put out. */ pcs->underline_enabled = false; pcl_home_cursor(pcs); pcl_xfm_reset_pcl_pat_ref_pt(pcs); if (!reset_initial) hpgl_do_reset(pcs, pcl_reset_page_params); if ( pcs->end_page == pcl_end_page_top ) { /* don't erase in snippet mode */ if (pcs->page_marked || changed_page_size) { gs_erasepage(pcs->pgs); pcs->page_marked = false; } } }
static int test5(gs_state * pgs, gs_memory_t * mem) { gx_device *dev = gs_currentdevice(pgs); gx_image_enum_common_t *info; gx_image_plane_t planes[5]; gx_drawing_color dcolor; int code; static const byte data3[] = { 0x00, 0x44, 0x88, 0xcc, 0x44, 0x88, 0xcc, 0x00, 0x88, 0xcc, 0x00, 0x44, 0xcc, 0x00, 0x44, 0x88 }; gs_color_space *gray_cs = gs_cspace_new_DeviceGray(mem); /* * Neither ImageType 3 nor 4 needs a current color, * but some intermediate code assumes it's valid. */ set_nonclient_dev_color(&dcolor, 0); /* Scale everything up, and fill the background. */ { gs_matrix mat; gs_currentmatrix(pgs, &mat); mat.xx = gs_copysign(98.6, mat.xx); mat.yy = gs_copysign(98.6, mat.yy); mat.tx = floor(mat.tx) + 0.499; mat.ty = floor(mat.ty) + 0.499; gs_setmatrix(pgs, &mat); } gs_setrgbcolor(pgs, 1.0, 0.9, 0.9); fill_rect1(pgs, 0.25, 0.25, 4.0, 6.0); gs_setrgbcolor(pgs, 0.5, 1.0, 0.5); #if 0 /* Make things a little more interesting.... */ gs_translate(pgs, 1.0, 1.0); gs_rotate(pgs, 10.0); gs_scale(pgs, 1.3, 0.9); #endif #define do_image(image, idata)\ BEGIN\ code = gx_device_begin_typed_image(dev, (gs_imager_state *)pgs, NULL,\ (gs_image_common_t *)&image, NULL, &dcolor, NULL, mem, &info);\ /****** TEST code >= 0 ******/\ planes[0].data = idata;\ planes[0].data_x = 0;\ planes[0].raster = (image.Height * image.BitsPerComponent + 7) >> 3;\ code = gx_image_plane_data(info, planes, image.Height);\ /****** TEST code == 1 ******/\ code = gx_image_end(info, true);\ /****** TEST code >= 0 ******/\ END #define W 4 #define H 4 /* Test an unmasked image. */ gs_gsave(pgs); { gs_image1_t image1; void *info1; gs_color_space *cs; cs = gs_cspace_new_DeviceGray(mem); gs_image_t_init(&image1, cs); /* image */ image1.ImageMatrix.xx = W; image1.ImageMatrix.yy = -H; image1.ImageMatrix.ty = H; /* data_image */ image1.Width = W; image1.Height = H; image1.BitsPerComponent = 8; gs_translate(pgs, 0.5, 4.0); code = gx_device_begin_image(dev, (gs_imager_state *) pgs, &image1, gs_image_format_chunky, NULL, &dcolor, NULL, mem, &info1); /****** TEST code >= 0 ******/ planes[0].data = data3; planes[0].data_x = 0; planes[0].raster = (image1.Height * image1.BitsPerComponent + 7) >> 3; /* Use the old image_data API. */ code = gx_image_data(info1, &planes[0].data, 0, planes[0].raster, image1.Height); /****** TEST code == 1 ******/ code = gx_image_end(info1, true); /****** TEST code >= 0 ******/ gs_free_object(mem, cs, "colorspace"); } gs_grestore(pgs); /* Test an explicitly masked image. */ gs_gsave(pgs); { gs_image3_t image3; static const byte data3mask[] = { 0x60, 0x90, 0x90, 0x60 }; static const byte data3x2mask[] = { 0x66, 0x99, 0x99, 0x66, 0x66, 0x99, 0x99, 0x66 }; gs_image3_t_init(&image3, gray_cs, interleave_scan_lines); /* image */ image3.ImageMatrix.xx = W; image3.ImageMatrix.yy = -H; image3.ImageMatrix.ty = H; /* data_image */ image3.Width = W; image3.Height = H; image3.BitsPerComponent = 8; /* MaskDict */ image3.MaskDict.ImageMatrix = image3.ImageMatrix; image3.MaskDict.Width = image3.Width; image3.MaskDict.Height = image3.Height; /* Display with 1-for-1 mask and image. */ gs_translate(pgs, 0.5, 2.0); code = gx_device_begin_typed_image(dev, (gs_imager_state *) pgs, NULL, (gs_image_common_t *) & image3, NULL, &dcolor, NULL, mem, &info); /****** TEST code >= 0 ******/ planes[0].data = data3mask; planes[0].data_x = 0; planes[0].raster = (image3.MaskDict.Height + 7) >> 3; planes[1].data = data3; planes[1].data_x = 0; planes[1].raster = (image3.Height * image3.BitsPerComponent + 7) >> 3; code = gx_image_plane_data(info, planes, image3.Height); /****** TEST code == 1 ******/ code = gx_image_end(info, true); /****** TEST code >= 0 ******/ /* Display with 2-for-1 mask and image. */ image3.MaskDict.ImageMatrix.xx *= 2; image3.MaskDict.ImageMatrix.yy *= 2; image3.MaskDict.ImageMatrix.ty *= 2; image3.MaskDict.Width *= 2; image3.MaskDict.Height *= 2; gs_translate(pgs, 1.5, 0.0); code = gx_device_begin_typed_image(dev, (gs_imager_state *) pgs, NULL, (gs_image_common_t *) & image3, NULL, &dcolor, NULL, mem, &info); /****** TEST code >= 0 ******/ planes[0].data = data3x2mask; planes[0].raster = (image3.MaskDict.Width + 7) >> 3; { int i; for (i = 0; i < H; ++i) { planes[1].data = 0; code = gx_image_plane_data(info, planes, 1); planes[0].data += planes[0].raster; /****** TEST code == 0 ******/ planes[1].data = data3 + i * planes[1].raster; code = gx_image_plane_data(info, planes, 1); planes[0].data += planes[0].raster; /****** TEST code >= 0 ******/ } } /****** TEST code == 1 ******/ code = gx_image_end(info, true); /****** TEST code >= 0 ******/ } gs_grestore(pgs); /* Test a chroma-keyed masked image. */ gs_gsave(pgs); { gs_image4_t image4; const byte *data4 = data3; gs_image4_t_init(&image4, gray_cs); /* image */ image4.ImageMatrix.xx = W; image4.ImageMatrix.yy = -H; image4.ImageMatrix.ty = H; /* data_image */ image4.Width = W; image4.Height = H; image4.BitsPerComponent = 8; /* Display with a single mask color. */ gs_translate(pgs, 0.5, 0.5); image4.MaskColor_is_range = false; image4.MaskColor[0] = 0xcc; do_image(image4, data4); /* Display a second time with a color range. */ gs_translate(pgs, 1.5, 0.0); image4.MaskColor_is_range = true; image4.MaskColor[0] = 0x40; image4.MaskColor[1] = 0x90; do_image(image4, data4); } gs_grestore(pgs); gs_free_object(mem, gray_cs, "test5 gray_cs"); #undef W #undef H #undef do_image return 0; }
static int pl_fapi_set_cache(gs_text_enum_t * penum, const gs_font_base * pbfont, const gs_string * char_name, int cid, const double pwidth[2], const gs_rect * pbbox, const double Metrics2_sbw_default[4], bool * imagenow) { gs_state *pgs = (gs_state *) penum->pis; float w2[6]; int code = 0; gs_fapi_server *I = pbfont->FAPI; if ((penum->text.operation & TEXT_DO_DRAW) && (pbfont->WMode & 1) && pwidth[0] == 1.0) { gs_rect tmp_pbbox; gs_matrix save_ctm; const gs_matrix id_ctm = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; /* This is kind of messy, but the cache entry has already been calculated using the in-force matrix. The problem is that we have to call gs_setcachedevice with the in-force matrix, not the rotated one, so we have to recalculate the extents to be correct for the rotated glyph. */ /* save the ctm */ gs_currentmatrix(pgs, &save_ctm); gs_setmatrix(pgs, &id_ctm); /* magic numbers - we don't completelely understand the translation magic used by HP. This provides a good approximation */ gs_translate(pgs, 1.0 / 1.15, -(1.0 - 1.0 / 1.15)); gs_rotate(pgs, 90); gs_transform(pgs, pbbox->p.x, pbbox->p.y, &tmp_pbbox.p); gs_transform(pgs, pbbox->q.x, pbbox->q.y, &tmp_pbbox.q); w2[0] = pwidth[0]; w2[1] = pwidth[1]; w2[2] = tmp_pbbox.p.x; w2[3] = tmp_pbbox.p.y; w2[4] = tmp_pbbox.q.x; w2[5] = tmp_pbbox.q.y; gs_setmatrix(pgs, &save_ctm); } else { w2[0] = pwidth[0]; w2[1] = pwidth[1]; w2[2] = pbbox->p.x; w2[3] = pbbox->p.y; w2[4] = pbbox->q.x; w2[5] = pbbox->q.y; } if (pbfont->PaintType) { double expand = max(1.415, gs_currentmiterlimit(pgs)) * gs_currentlinewidth(pgs) / 2; w2[2] -= expand; w2[3] -= expand; w2[4] += expand; w2[5] += expand; } if (I->ff.embolden != 0) { code = gs_setcharwidth((gs_show_enum *) penum, pgs, w2[0], w2[1]); } else { if ((code = gs_setcachedevice((gs_show_enum *) penum, pgs, w2)) < 0) { return (code); } } if ((penum->text.operation & TEXT_DO_DRAW) && (pbfont->WMode & 1) && pwidth[0] == 1.0) { *imagenow = false; return (gs_error_unknownerror); } *imagenow = true; return (code); }
int pxSetLineDash(px_args_t *par, px_state_t *pxs) { px_gstate_t *pxgs = pxs->pxgs; gs_state *pgs = pxs->pgs; if ( par->pv[0] ) { float pattern[MAX_DASH_ELEMENTS * 2]; uint size = par->pv[0]->value.array.size; real offset = (par->pv[1] ? real_value(par->pv[1], 0) : 0.0); int code; if ( par->pv[2] ) return_error(errorIllegalAttributeCombination); if ( size > MAX_DASH_ELEMENTS ) return_error(errorIllegalArraySize); /* * The H-P documentation gives no clue about what a negative * dash pattern element is supposed to do. The H-P printers * apparently interpret it as drawing a line backwards in the * current direction (which may extend outside the original * subpath) with the caps inside the line instead of outside; a * dash pattern with a negative total length crashes the LJ 6MP * firmware so badly the printer has to be power cycled! We * take a different approach here: we compensate for negative * elements by propagating them to adjacent positive ones. This * doesn't produce quite the same output as the H-P printers do, * but this is such an obscure feature that we don't think it's * worth the trouble to emulate exactly. */ { uint orig_size = size; int i; /* Acquire the pattern, duplicating it if the length is odd. */ if ( size & 1 ) size <<= 1; for ( i = 0; i < size; ++i ) pattern[i] = real_elt(par->pv[0], i % orig_size); /* Get rid of negative draws. */ if ( pattern[0] < 0 ) offset -= pattern[0], pattern[size - 1] += pattern[0], pattern[1] += pattern[0], pattern[0] = -pattern[0]; for ( i = 2; i < size; i += 2 ) if ( pattern[i] < 0 ) pattern[i - 1] += pattern[i], pattern[i + 1] += pattern[i], pattern[i] = -pattern[i]; /* * Now propagate negative skips iteratively. Since each step * decreases either the remaining total of negative skips or * the total number of pattern elements, the process is * guaranteed to terminate. */ elim: for ( i = 0; i < size; i += 2 ) { float draw = pattern[i], skip = pattern[i + 1]; int inext, iprev; float next, prev; if ( skip > 0 ) continue; if ( size == 2 ) /* => i == 0 */ { if ( (pattern[0] = draw + skip) <= 0 ) pattern[0] = -pattern[0]; pattern[1] = 0; break; } inext = (i == size - 2 ? 0 : i + 2); next = pattern[inext]; /* * Consider the sequence D, -S, E, where D and E are draws * and -S is a negative skip. If S <= D, replace the 3 * elements with D - S + E. */ if ( draw + skip >= 0 ) { next += draw + skip; goto shrink; } /* * Otherwise, let T be the skip preceding D. Replace T * with T + D - S. If S > E, replace D, -S, E with E, S - * (D + E), D; otherwise, replace D, -S, E with E. In * both cases, net progress has occurred. */ iprev = (i == 0 ? size - 1 : i - 1); prev = pattern[iprev]; pattern[iprev] = prev + draw + skip; if ( -skip > next ) { pattern[i] = next; pattern[i + 1] = -(skip + draw + next); pattern[i + 2] = draw; goto elim; } shrink: if ( inext == 0 ) { offset += next - pattern[0]; pattern[0] = next; } else { pattern[i] = next; memmove(&pattern[i + 1], &pattern[i + 3], (size - (i + 3)) * sizeof(pattern[0])); } size -= 2; goto elim; } } code = gs_setdash(pgs, pattern, size, offset); if ( code < 0 ) return code; /* patterns with 0 total skip length are treated as solid line pattern on the LJ6 */ { bool skips_have_length = false; int i; for ( i = 0; i < size; i += 2 ) if ( pattern[i + 1] != 0 ) { skips_have_length = true; break; } if ( skips_have_length == false ) { pxgs->dashed = false; return gs_setdash(pgs, NULL, 0, 0.0); } pxgs->dashed = (size != 0); } gs_currentmatrix(pgs, &pxgs->dash_matrix); return 0; } else if ( par->pv[2] ) { if ( par->pv[1] ) return_error(errorIllegalAttributeCombination); pxgs->dashed = false; return gs_setdash(pgs, NULL, 0, 0.0); } else return_error(errorMissingAttribute); }