コード例 #1
0
ファイル: zupath.c プロジェクト: BorodaZizitopa/ghostscript
/* <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;
}
コード例 #2
0
ファイル: pgconfig.c プロジェクト: ststeiger/ghostsvg
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;
}
コード例 #3
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;
}
コード例 #4
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;
}
コード例 #5
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;
}
コード例 #6
0
ファイル: zmatrix.c プロジェクト: computersforpeace/ghostpdl
/* - .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;
}
コード例 #7
0
ファイル: plfapi.c プロジェクト: hackqiang/gs
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);
}
コード例 #8
0
ファイル: pgfont.c プロジェクト: ststeiger/ghostsvg
/* 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;
}
コード例 #9
0
ファイル: pcpage.c プロジェクト: ststeiger/ghostsvg
/*
 * 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;
        }
    }
}
コード例 #10
0
ファイル: gslib.c プロジェクト: BorodaZizitopa/ghostscript
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;
}
コード例 #11
0
ファイル: plfapi.c プロジェクト: hackqiang/gs
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);
}
コード例 #12
0
ファイル: pxgstate.c プロジェクト: ststeiger/ghostsvg
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);
}