gdev_x_open(gx_device_X * xdev)
{
    XSizeHints sizehints;
    char *window_id;
    XEvent event;
    XVisualInfo xvinfo;
    int nitems;
    XtAppContext app_con;
    Widget toplevel;
    Display *dpy;
    XColor xc;
    int zero = 0;
    int xid_height = 0, xid_width = 0;
    int code;

#ifdef DEBUG
# ifdef have_Xdebug
    if (gs_debug['X']) {
        extern int _Xdebug;

        _Xdebug = 1;
    }
# endif
#endif
    if (!(xdev->dpy = XOpenDisplay((char *)NULL))) {
        char *dispname = getenv("DISPLAY");

        emprintf1(xdev->memory,
                  "Cannot open X display `%s'.\n",
                 (dispname == NULL ? "(null)" : dispname));
        return_error(gs_error_ioerror);
    }
    xdev->dest = 0;
    if ((window_id = getenv("GHOSTVIEW"))) {
        if (!(xdev->ghostview = sscanf(window_id, "%ld %ld",
                                       &(xdev->win), &(xdev->dest)))) {
            emprintf(xdev->memory, "Cannot get Window ID from ghostview.\n");
            return_error(gs_error_ioerror);
        }
    }
    if (xdev->pwin != (Window) None) {	/* pick up the destination window parameters if specified */
        XWindowAttributes attrib;

        xdev->win = xdev->pwin;
        if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
            xdev->scr = attrib.screen;
            xvinfo.visual = attrib.visual;
            xdev->cmap = attrib.colormap;
            xid_width = attrib.width;
            xid_height = attrib.height;
        } else {
            /* No idea why we can't get the attributes, but */
            /* we shouldn't let it lead to a failure below. */
            xid_width = xid_height = 0;
        }
    } else if (xdev->ghostview) {
        XWindowAttributes attrib;
        Atom type;
        int format;
        unsigned long nitems, bytes_after;
        char *buf;
        Atom ghostview_atom = XInternAtom(xdev->dpy, "GHOSTVIEW", False);

        if (XGetWindowAttributes(xdev->dpy, xdev->win, &attrib)) {
            xdev->scr = attrib.screen;
            xvinfo.visual = attrib.visual;
            xdev->cmap = attrib.colormap;
            xdev->width = attrib.width;
            xdev->height = attrib.height;
        }
        /* Delete property if explicit dest is given */
        if (XGetWindowProperty(xdev->dpy, xdev->win, ghostview_atom, 0,
                               256, (xdev->dest != 0), XA_STRING,
                               &type, &format, &nitems, &bytes_after,
                               (unsigned char **)&buf) == 0 &&
            type == XA_STRING) {
            int llx, lly, urx, ury;
            int left_margin = 0, bottom_margin = 0;
            int right_margin = 0, top_margin = 0;

            /* We declare page_orientation as an int so that we can */
            /* use an int * to reference it for sscanf; compilers */
            /* might be tempted to use less space to hold it if */
            /* it were declared as an orientation. */
            int /*orientation */ page_orientation;
            float xppp, yppp;	/* pixels per point */

            nitems = sscanf(buf,
                            "%ld %d %d %d %d %d %f %f %d %d %d %d",
                            &(xdev->bpixmap), &page_orientation,
                            &llx, &lly, &urx, &ury,
                            &(xdev->x_pixels_per_inch),
                            &(xdev->y_pixels_per_inch),
                            &left_margin, &bottom_margin,
                            &right_margin, &top_margin);
            if (!(nitems == 8 || nitems == 12)) {
                emprintf(xdev->memory, "Cannot get ghostview property.\n");
                return_error(gs_error_ioerror);
            }
            if (xdev->dest && xdev->bpixmap) {
                emprintf(xdev->memory,
                         "Both destination and backing pixmap specified.\n");
                return_error(gs_error_rangecheck);
            }
            if (xdev->dest) {
                Window root;
                int x, y;
                unsigned int width, height;
                unsigned int border_width, depth;

                if (XGetGeometry(xdev->dpy, xdev->dest, &root, &x, &y,
                                 &width, &height, &border_width, &depth)) {
                    xdev->width = width;
                    xdev->height = height;
                }
            }
            xppp = xdev->x_pixels_per_inch / 72.0;
            yppp = xdev->y_pixels_per_inch / 72.0;
            switch (page_orientation) {
                case Portrait:
                    xdev->initial_matrix.xx = xppp;
                    xdev->initial_matrix.xy = 0.0;
                    xdev->initial_matrix.yx = 0.0;
                    xdev->initial_matrix.yy = -yppp;
                    xdev->initial_matrix.tx = -llx * xppp;
                    xdev->initial_matrix.ty = ury * yppp;
                    break;
                case Landscape:
                    xdev->initial_matrix.xx = 0.0;
                    xdev->initial_matrix.xy = yppp;
                    xdev->initial_matrix.yx = xppp;
                    xdev->initial_matrix.yy = 0.0;
                    xdev->initial_matrix.tx = -lly * xppp;
                    xdev->initial_matrix.ty = -llx * yppp;
                    break;
                case Upsidedown:
                    xdev->initial_matrix.xx = -xppp;
                    xdev->initial_matrix.xy = 0.0;
                    xdev->initial_matrix.yx = 0.0;
                    xdev->initial_matrix.yy = yppp;
                    xdev->initial_matrix.tx = urx * xppp;
                    xdev->initial_matrix.ty = -lly * yppp;
                    break;
                case Seascape:
                    xdev->initial_matrix.xx = 0.0;
                    xdev->initial_matrix.xy = -yppp;
                    xdev->initial_matrix.yx = -xppp;
                    xdev->initial_matrix.yy = 0.0;
                    xdev->initial_matrix.tx = ury * xppp;
                    xdev->initial_matrix.ty = urx * yppp;
                    break;
            }

            /* The following sets the imageable area according to the */
            /* bounding box and margins sent by ghostview.            */
            /* This code has been patched many times; its current state */
            /* is per a recommendation by Tim Theisen on 4/28/95. */

            xdev->ImagingBBox[0] = llx - left_margin;
            xdev->ImagingBBox[1] = lly - bottom_margin;
            xdev->ImagingBBox[2] = urx + right_margin;
            xdev->ImagingBBox[3] = ury + top_margin;
            xdev->ImagingBBox_set = true;

        } else if (xdev->pwin == (Window) None) {
            emprintf(xdev->memory, "Cannot get ghostview property.\n");
            return_error(gs_error_ioerror);
        }
    } else {
        Screen *scr = DefaultScreenOfDisplay(xdev->dpy);

        xdev->scr = scr;
        xvinfo.visual = DefaultVisualOfScreen(scr);
        xdev->cmap = DefaultColormapOfScreen(scr);
        if (xvinfo.visual->class != TrueColor) {
            int scrno = DefaultScreen(xdev->dpy);
            if ( XMatchVisualInfo(xdev->dpy, scrno, 24, TrueColor, &xvinfo) ||
                 XMatchVisualInfo(xdev->dpy, scrno, 32, TrueColor, &xvinfo) ||
                 XMatchVisualInfo(xdev->dpy, scrno, 16, TrueColor, &xvinfo) ||
                 XMatchVisualInfo(xdev->dpy, scrno, 15, TrueColor, &xvinfo)  ) {
                xdev->cmap = XCreateColormap (xdev->dpy,
                                              DefaultRootWindow(xdev->dpy),
                                              xvinfo.visual, AllocNone );
            }
        }
    }
    xvinfo.visualid = XVisualIDFromVisual(xvinfo.visual);
    xdev->vinfo = XGetVisualInfo(xdev->dpy, VisualIDMask, &xvinfo, &nitems);
    if (xdev->vinfo == NULL) {
        emprintf(xdev->memory, "Cannot get XVisualInfo.\n");
        return_error(gs_error_ioerror);
    }
    /* Buggy X servers may cause a Bad Access on XFreeColors. */
    if (!x_error_handler.set) {
        x_error_handler.orighandler = XSetErrorHandler(x_catch_free_colors);
        x_error_handler.set = True;
    }
    /* Get X Resources.  Use the toolkit for this. */
    XtToolkitInitialize();
    app_con = XtCreateApplicationContext();
    XtAppSetFallbackResources(app_con, gdev_x_fallback_resources);
    dpy = XtOpenDisplay(app_con, NULL, "ghostscript", "Ghostscript",
                        NULL, 0, &zero, NULL);
    toplevel = XtAppCreateShell(NULL, "Ghostscript",
                                applicationShellWidgetClass, dpy, NULL, 0);
    XtGetApplicationResources(toplevel, (XtPointer) xdev,
                              gdev_x_resources, gdev_x_resource_count,
                              NULL, 0);

    /* Reserve foreground and background colors under the regular connection. */
    xc.pixel = xdev->foreground;
    XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
    XAllocColor(xdev->dpy, xdev->cmap, &xc);
    xdev->foreground = xc.pixel;
    xc.pixel = xdev->background;
    XQueryColor(xdev->dpy, DefaultColormap(xdev->dpy,DefaultScreen(xdev->dpy)), &xc);
    XAllocColor(xdev->dpy, xdev->cmap, &xc);
    xdev->background = xc.pixel;

    code = gdev_x_setup_colors(xdev);
    if (code < 0) {
        XCloseDisplay(xdev->dpy);
        return code;
    }
    /* Now that the color map is setup check if the device is separable. */
    check_device_separable((gx_device *)xdev);

    if (!xdev->ghostview) {
        XWMHints wm_hints;
        XClassHint class_hint;
        XSetWindowAttributes xswa;
        gx_device *dev = (gx_device *) xdev;

        /* Take care of resolution and paper size. */
        if (xdev->x_pixels_per_inch == FAKE_RES ||
            xdev->y_pixels_per_inch == FAKE_RES) {
            float xsize = (float)xdev->width / xdev->x_pixels_per_inch;
            float ysize = (float)xdev->height / xdev->y_pixels_per_inch;
            int workarea_width = WidthOfScreen(xdev->scr), workarea_height = HeightOfScreen(xdev->scr);

            /* Get area available for windows placement */
            x_get_work_area(xdev, &workarea_width, &workarea_height);

            if (xdev->xResolution == 0.0 && xdev->yResolution == 0.0) {
                float dpi, xdpi, ydpi;

                xdpi = 25.4 * WidthOfScreen(xdev->scr) /
                    WidthMMOfScreen(xdev->scr);
                ydpi = 25.4 * HeightOfScreen(xdev->scr) /
                    HeightMMOfScreen(xdev->scr);
                dpi = min(xdpi, ydpi);
                /*
                 * Some X servers provide very large "virtual screens", and
                 * return the virtual screen size for Width/HeightMM but the
                 * physical size for Width/Height.  Attempt to detect and
                 * correct for this now.  This is a KLUDGE required because
                 * the X server provides no way to read the screen
                 * resolution directly.
                 */
                if (dpi < 30)
                    dpi = 75;	/* arbitrary */
                else {
                    while (xsize * dpi > WidthOfScreen(xdev->scr) - 32 ||
                           ysize * dpi > HeightOfScreen(xdev->scr) - 32)
                        dpi *= 0.95;
                }
                xdev->x_pixels_per_inch = dpi;
                xdev->y_pixels_per_inch = dpi;
            } else {
                xdev->x_pixels_per_inch = xdev->xResolution;
                xdev->y_pixels_per_inch = xdev->yResolution;
            }
            /* Restrict maximum window size to available work area */
            if (xdev->width > workarea_width) {
                xdev->width = min(xsize * xdev->x_pixels_per_inch, workarea_width);
            }
            if (xdev->height > workarea_height) {
                xdev->height = min(ysize * xdev->y_pixels_per_inch, workarea_height);
            }
            xdev->MediaSize[0] =
                (float)xdev->width / xdev->x_pixels_per_inch * 72;
            xdev->MediaSize[1] =
                (float)xdev->height / xdev->y_pixels_per_inch * 72;
        }

        sizehints.x = 0;
        sizehints.y = 0;
        sizehints.width = xdev->width;
        sizehints.height = xdev->height;
        sizehints.flags = 0;

        if (xdev->geometry != NULL) {
            /*
             * Note that border_width must be set first.  We can't use
             * scr, because that is a Screen*, and XWMGeometry wants
             * the screen number.
             */
            char gstr[40];
            int bitmask;

            gs_sprintf(gstr, "%dx%d+%d+%d", sizehints.width,
                    sizehints.height, sizehints.x, sizehints.y);
            bitmask = XWMGeometry(xdev->dpy, DefaultScreen(xdev->dpy),
                                  xdev->geometry, gstr, xdev->borderWidth,
                                  &sizehints,
                                  &sizehints.x, &sizehints.y,
                                  &sizehints.width, &sizehints.height,
                                  &sizehints.win_gravity);

            if (bitmask & (XValue | YValue))
                sizehints.flags |= USPosition;
        }
        gx_default_get_initial_matrix(dev, &(xdev->initial_matrix));

        if (xdev->pwin != (Window) None && xid_width != 0 && xid_height != 0) {
#if 0				/*************** */

            /*
             * The user who originally implemented the WindowID feature
             * provided the following code to scale the displayed output
             * to fit in the window.  We think this is a bad idea,
             * since it doesn't track window resizing and is generally
             * completely at odds with the way Ghostscript treats
             * window or paper size in all other contexts.  We are
             * leaving the code here in case someone decides that
             * this really is the behavior they want.
             */

            /* Scale to fit in the window. */
            xdev->initial_matrix.xx
                = xdev->initial_matrix.xx *
                (float)xid_width / (float)xdev->width;
            xdev->initial_matrix.yy
                = xdev->initial_matrix.yy *
                (float)xid_height / (float)xdev->height;

#endif /*************** */
            xdev->width = xid_width;
            xdev->height = xid_height;
            xdev->initial_matrix.ty = xdev->height;
        } else {		/* !xdev->pwin */
            xswa.event_mask = ExposureMask;
            xswa.background_pixel = xdev->background;
            xswa.border_pixel = xdev->borderColor;
            xswa.colormap = xdev->cmap;
            xdev->win = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
                                      sizehints.x, sizehints.y,		/* upper left */
                                      xdev->width, xdev->height,
                                      xdev->borderWidth,
                                      xdev->vinfo->depth,
                                      InputOutput,	/* class        */
                                      xdev->vinfo->visual,	/* visual */
                                      CWEventMask | CWBackPixel |
                                      CWBorderPixel | CWColormap,
                                      &xswa);
            XStoreName(xdev->dpy, xdev->win, "ghostscript");
            XSetWMNormalHints(xdev->dpy, xdev->win, &sizehints);
            wm_hints.flags = InputHint;
            wm_hints.input = False;
            XSetWMHints(xdev->dpy, xdev->win, &wm_hints);	/* avoid input focus */
            class_hint.res_name = (char *)"ghostscript";
            class_hint.res_class = (char *)"Ghostscript";
            XSetClassHint(xdev->dpy, xdev->win, &class_hint);
        }
    }
    /***
     *** According to Ricard Torres (torres@upf.es), we have to wait until here
     *** to close the toolkit connection, which we formerly did
     *** just after the calls on XAllocColor above.  I suspect that
     *** this will cause things to be left dangling if an error occurs
     *** anywhere in the above code, but I'm willing to let users
     *** fight over fixing it, since I have no idea what's right.
     ***/

    /* And close the toolkit connection. */
    XtDestroyWidget(toplevel);
    XtCloseDisplay(dpy);
    XtDestroyApplicationContext(app_con);

    xdev->ht.pixmap = (Pixmap) 0;
    xdev->ht.id = gx_no_bitmap_id;;
    xdev->fill_style = FillSolid;
    xdev->function = GXcopy;
    xdev->fid = (Font) 0;

    /* Set up a graphics context */
    xdev->gc = XCreateGC(xdev->dpy, xdev->win, 0, (XGCValues *) NULL);
    XSetFunction(xdev->dpy, xdev->gc, GXcopy);
    XSetLineAttributes(xdev->dpy, xdev->gc, 0,
                       LineSolid, CapButt, JoinMiter);

    gdev_x_clear_window(xdev);

    if (!xdev->ghostview) {	/* Make the window appear. */
        XMapWindow(xdev->dpy, xdev->win);

        /* Before anything else, do a flush and wait for */
        /* an exposure event. */
        XSync(xdev->dpy, False);
        if (xdev->pwin == (Window) None) {	/* there isn't a next event for existing windows */
            XNextEvent(xdev->dpy, &event);
        }
        /* Now turn off graphics exposure events so they don't queue up */
        /* indefinitely.  Also, since we can't do anything about real */
        /* Expose events, mask them out. */
        XSetGraphicsExposures(xdev->dpy, xdev->gc, False);
        XSelectInput(xdev->dpy, xdev->win, NoEventMask);
    } else {
        /* Create an unmapped window, that the window manager will ignore.
         * This invisible window will be used to receive "next page"
         * events from ghostview */
        XSetWindowAttributes attributes;

        attributes.override_redirect = True;
        xdev->mwin = XCreateWindow(xdev->dpy, RootWindowOfScreen(xdev->scr),
                                   0, 0, 1, 1, 0, CopyFromParent,
                                   CopyFromParent, CopyFromParent,
                                   CWOverrideRedirect, &attributes);
        xdev->NEXT = XInternAtom(xdev->dpy, "NEXT", False);
        xdev->PAGE = XInternAtom(xdev->dpy, "PAGE", False);
        xdev->DONE = XInternAtom(xdev->dpy, "DONE", False);
    }

    xdev->ht.no_pixmap = XCreatePixmap(xdev->dpy, xdev->win, 1, 1,
                                       xdev->vinfo->depth);

    return 0;
}


pdf14_tile_pattern_fill(gx_device * pdev, const gs_gstate * pgs,
                        gx_path * ppath, const gx_fill_params * params,
                        const gx_device_color * pdevc,
                        const gx_clip_path * pcpath)
{
    int code;
    gs_gstate *pgs_noconst = (gs_gstate *)pgs; /* Break const. */
    gs_fixed_rect clip_box;
    gs_fixed_rect outer_box;
    pdf14_device * p14dev = (pdf14_device *)pdev;
    gs_int_rect rect;
    gx_clip_rect *curr_clip_rect;
    gx_color_tile *ptile = NULL;
    int k;
    gx_pattern_trans_t *fill_trans_buffer = NULL;
    gs_int_point phase;  /* Needed during clist rendering for band offset */
    int n_chan_tile;
    gx_clip_path cpath_intersection;
    gx_path path_ttrans;
    gs_blend_mode_t blend_mode;

    if (ppath == NULL)
        return_error(gs_error_unknownerror);	/* should not happen */
    if (pcpath != NULL) {
        code = gx_cpath_init_local_shared_nested(&cpath_intersection, pcpath, ppath->memory, 1);
    } else {
        (*dev_proc(pdev, get_clipping_box)) (pdev, &clip_box);
        gx_cpath_init_local(&cpath_intersection, ppath->memory);
        code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box);
    }
    if (code < 0)
        return code;
    code = gx_cpath_intersect_with_params(&cpath_intersection, ppath,
                                          params->rule, pgs_noconst, params);
    if (code < 0)
        return code;
    /* One (common) case worth optimising for is where we have a pattern that
     * is positioned such that only one repeat of the tile is actually
     * visible. In this case, we can restrict the size of the blending group
     * we need to produce to be that of the actual area of the tile that is
     * used. */
    ptile = pdevc->colors.pattern.p_tile;
    if (ptile->ttrans != NULL)
    {
        if ((cpath_intersection.outer_box.p.x < 0) ||
            (cpath_intersection.outer_box.p.y < 0) ||
            (cpath_intersection.outer_box.q.x > int2fixed(ptile->ttrans->width)) ||
            (cpath_intersection.outer_box.q.y > int2fixed(ptile->ttrans->height)))
        {
            /* More than one repeat of the tile would be visible, so we can't
             * use the optimisation here. (Actually, this test isn't quite
             * right - it actually tests whether more than the '0th' repeat
             * of the tile is visible. A better test would test if just one
             * repeat of the tile was visible, irrespective of which one.
             * This is (hopefully) relatively rare, and would make the code
             * below more complex too, so we're ignoring that for now. If it
             * becomes evident that it's a case that matters we can revisit
             * it.) */
        } else {
            /* Only the 0th repeat is visible. Restrict the size further to
             * just the used area of that patch. */
            gx_path_init_local(&path_ttrans, ppath->memory);
            code = gx_path_add_rectangle(&path_ttrans,
                                         int2fixed(ptile->ttrans->rect.p.x),
                                         int2fixed(ptile->ttrans->rect.p.y),
                                         int2fixed(ptile->ttrans->rect.q.x),
                                         int2fixed(ptile->ttrans->rect.q.y));
            if (code < 0)
                return code;
            code = gx_cpath_intersect(&cpath_intersection, &path_ttrans,
                                      params->rule, pgs_noconst);
            if (code < 0)
                return code;
        }
    }
    /* Now let us push a transparency group into which we are
     * going to tile the pattern.  */
    if (ppath != NULL && code >= 0) {
        pdf14_device save_pdf14_dev;		/* save area for p14dev */

        gx_cpath_outer_box(&cpath_intersection, &outer_box);
        rect.p.x = fixed2int(outer_box.p.x);
        rect.p.y = fixed2int(outer_box.p.y);
        rect.q.x = fixed2int_ceiling(outer_box.q.x);
        rect.q.y = fixed2int_ceiling(outer_box.q.y);

        /* The color space of this group must be the same as that of the
           tile.  Then when we pop the group, if there is a mismatch between
           the tile color space and the current context we will do the proper
           conversion.  In this way, we ensure that if the tile has any overlapping
           occuring it will be blended in the proper manner i.e in the tile
           underlying color space. */
        if (ptile->cdev == NULL) {
            if (ptile->ttrans == NULL)
                return_error(gs_error_unknownerror);	/* should not happen */
            n_chan_tile = ptile->ttrans->n_chan;
        } else {
            n_chan_tile = ptile->cdev->common.color_info.num_components+1;
        }
        blend_mode = ptile->blending_mode;
        memcpy(&save_pdf14_dev, p14dev, sizeof(pdf14_device));
        code = pdf14_push_transparency_group(p14dev->ctx, &rect, 1, 0, 255,255,
                                             blend_mode, 0, 0, n_chan_tile-1,
                                             false, NULL, NULL, pgs_noconst,
                                             pdev);
        if (code < 0)
            return code;

        /* Set the blending procs and the is_additive setting based
           upon the number of channels */
        if (ptile->cdev == NULL) {
            if (n_chan_tile-1 < 4) {
                ptile->ttrans->blending_procs = &rgb_blending_procs;
                ptile->ttrans->is_additive = true;
            } else {
                ptile->ttrans->blending_procs = &cmyk_blending_procs;
                ptile->ttrans->is_additive = false;
            }
        }
        /* Now lets go through the rect list and fill with the pattern */
        /* First get the buffer that we will be filling */
        if (ptile->cdev == NULL) {
            fill_trans_buffer = new_pattern_trans_buff(pgs->memory);
            pdf14_get_buffer_information(pdev, fill_trans_buffer, NULL, false);
            /* Based upon if the tiles overlap pick the type of rect fill that we will
               want to use */
            if (ptile->has_overlap) {
                /* This one does blending since there is tile overlap */
                ptile->ttrans->pat_trans_fill = &tile_rect_trans_blend;
            } else {
                /* This one does no blending since there is no tile overlap */
                ptile->ttrans->pat_trans_fill = &tile_rect_trans_simple;
            }
            /* fill the rectangles */
            phase.x = pdevc->phase.x;
            phase.y = pdevc->phase.y;
            if (cpath_intersection.rect_list->list.head != NULL){
                curr_clip_rect = cpath_intersection.rect_list->list.head->next;
                for( k = 0; k < cpath_intersection.rect_list->list.count && code >= 0; k++){
                    if_debug5m('v', pgs->memory,
                               "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %d \n",
                               curr_clip_rect->xmin, curr_clip_rect->ymin,
                               curr_clip_rect->xmax-curr_clip_rect->xmin,
                               curr_clip_rect->ymax-curr_clip_rect->ymin, (int)ptile->id);
                    code = gx_trans_pattern_fill_rect(curr_clip_rect->xmin, curr_clip_rect->ymin,
                                                      curr_clip_rect->xmax, curr_clip_rect->ymax, ptile,
                                                      fill_trans_buffer, phase, pdev, pdevc);
                    curr_clip_rect = curr_clip_rect->next;
                }
            } else if (cpath_intersection.rect_list->list.count == 1) {
                /* The case when there is just a single rect */
                if_debug5m('v', pgs->memory,
                           "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %d \n",
                           cpath_intersection.rect_list->list.single.xmin,
                           cpath_intersection.rect_list->list.single.ymin,
                           cpath_intersection.rect_list->list.single.xmax-
                              cpath_intersection.rect_list->list.single.xmin,
                           cpath_intersection.rect_list->list.single.ymax-
                              cpath_intersection.rect_list->list.single.ymin,
                           (int)ptile->id);
                code = gx_trans_pattern_fill_rect(cpath_intersection.rect_list->list.single.xmin,
                                                  cpath_intersection.rect_list->list.single.ymin,
                                                  cpath_intersection.rect_list->list.single.xmax,
                                                  cpath_intersection.rect_list->list.single.ymax,
                                                  ptile, fill_trans_buffer, phase, pdev, pdevc);
            }
        } else {
            /* Clist pattern with transparency.  Create a clip device from our
               cpath_intersection.  The above non-clist case could probably be
               done this way too, which will reduce the amount of code here.
               That is for another day though due to time constraints*/
            gx_device *dev;
            gx_device_clip clipdev;

            gx_make_clip_device_on_stack(&clipdev, &cpath_intersection, pdev);
            dev = (gx_device *)&clipdev;
            phase.x = pdevc->phase.x;
            phase.y = pdevc->phase.y;
            code = gx_trans_pattern_fill_rect(rect.p.x, rect.p.y, rect.q.x, rect.q.y,
                                              ptile, fill_trans_buffer, phase,
                                              dev, pdevc);

        }
        /* We're done drawing with the pattern, remove the reference to the
         * pattern device
         */
        p14dev->pclist_device = NULL;
        if (code < 0)
            return code;

        /* free our buffer object */
        if (fill_trans_buffer != NULL) {
            gs_free_object(pgs->memory, fill_trans_buffer, "pdf14_tile_pattern_fill");
            ptile->ttrans->fill_trans_buffer = NULL;  /* Avoid GC issues */
        }
        /* pop our transparency group which will force the blending.
           This was all needed for Bug 693498 */
        code = pdf14_pop_transparency_group(pgs_noconst, p14dev->ctx,
                                            p14dev->blend_procs,
                                            p14dev->color_info.num_components,
                                            p14dev->icc_struct->device_profile[0],
                                            pdev);
        memcpy(p14dev, &save_pdf14_dev, sizeof(pdf14_device));
        p14dev->pclist_device = NULL;
    }
    return code;
}


pdf14_push_transparency_group(pdf14_ctx	*ctx, gs_int_rect *rect, bool isolated,
                              bool knockout, byte alpha, byte shape,
                              gs_blend_mode_t blend_mode, bool idle, uint mask_id,
                              int numcomps, bool cm_back_drop,
                              cmm_profile_t *group_profile,
                              cmm_profile_t *tos_profile, gs_gstate *pgs,
                              gx_device *dev)
{
    pdf14_buf *tos = ctx->stack;
    pdf14_buf *buf, *backdrop;
    bool has_shape, has_tags;

    if_debug1m('v', ctx->memory,
               "[v]pdf14_push_transparency_group, idle = %d\n", idle);

    /* We are going to use the shape in the knockout computation.  If previous
       buffer has a shape or if this is a knockout then we will have a shape here */
    has_shape = tos->has_shape || tos->knockout;
   // has_shape = false;
    /* If previous buffer has tags, then add tags here */
    has_tags = tos->has_tags;

    /* If the group is NOT isolated we add in the alpha_g plane.  This enables
       recompositing to be performed ala art_pdf_recomposite_group_8 so that
       the backdrop is only included one time in the computation. */
    /* Order of buffer data is color data, followed by alpha channel, followed by
       shape (if present), then alpha_g (if present), then tags (if present) */
    buf = pdf14_buf_new(rect, has_tags, !isolated, has_shape, idle, numcomps + 1,
                        tos->num_spots, ctx->memory);
    if (buf == NULL)
        return_error(gs_error_VMerror);
    if_debug4m('v', ctx->memory,
        "[v]base buf: %d x %d, %d color channels, %d planes\n",
        buf->rect.q.x, buf->rect.q.y, buf->n_chan, buf->n_planes);
    buf->isolated = isolated;
    buf->knockout = knockout;
    buf->alpha = alpha;
    buf->shape = shape;
    buf->blend_mode = blend_mode;
    buf->mask_id = mask_id;
    buf->mask_stack = ctx->mask_stack; /* Save because the group rendering may
                                          set up another (nested) mask. */
    ctx->mask_stack = NULL; /* Clean the mask field for rendering this group.
                            See pdf14_pop_transparency_group how to handle it. */
    buf->saved = tos;
    ctx->stack = buf;
    if (buf->data == NULL)
        return 0;
    if (idle)
        return 0;
    backdrop = pdf14_find_backdrop_buf(ctx);
    if (backdrop == NULL) {
        /* Note, don't clear out tags set by pdf14_buf_new == GS_UNKNOWN_TAG */
        memset(buf->data, 0, buf->planestride * (buf->n_chan +
                                                 (buf->has_shape ? 1 : 0) +
                                                 (buf->has_alpha_g ? 1 : 0)));
    } else {
        if (!buf->knockout) {
            if (!cm_back_drop) {
                pdf14_preserve_backdrop(buf, tos, false);
            } else {
                /* We must have an non-isolated group with a mismatch in color spaces.
                   In this case, we can't just copy the buffer but must CM it */
                pdf14_preserve_backdrop_cm(buf, group_profile, tos, tos_profile,
                                           ctx->memory, pgs, dev, false);
            }
        }
    }

    /* If knockout, we have to maintain a copy of the backdrop in case we are
       drawing nonisolated groups on top of the knockout group. */
    if (buf->knockout) {
        buf->backdrop = gs_alloc_bytes(ctx->memory, buf->planestride * buf->n_chan,
                                        "pdf14_push_transparency_group");
        if (buf->backdrop == NULL) {
            return gs_throw(gs_error_VMerror, "Knockout backdrop allocation failed");
        }
        if (buf->isolated) {
            /* We will have opaque backdrop for non-isolated compositing */
            memset(buf->backdrop, 0, buf->planestride * buf->n_chan);
        } else {
            /* Save knockout backdrop for non-isolated compositing */
            /* Note that we need to drill down through the non-isolated groups in our
               stack and make sure that we are not embedded in another knockout group */
            pdf14_buf *check = tos;
            pdf14_buf *child = NULL;  /* Needed so we can get profile */
            cmm_profile_t *prev_knockout_profile;

            while (check != NULL) {
                if (check->isolated)
                    break;
                if (check->knockout) {
                    break;
                }
                child = check;
                check = check->saved;
            }
            /* Here we need to grab a back drop from a knockout parent group and
                potentially worry about color differences. */
            if (check == NULL) {
                prev_knockout_profile = tos_profile;
                check = tos;
            } else {
                if (child == NULL) {
                    prev_knockout_profile = tos_profile;
                } else {
                    prev_knockout_profile  = child->parent_color_info_procs->icc_profile;
                }
            }
            if (!cm_back_drop) {
                pdf14_preserve_backdrop(buf, check, false);
            } else {
                /* We must have an non-isolated group with a mismatch in color spaces.
                   In this case, we can't just copy the buffer but must CM it */
                pdf14_preserve_backdrop_cm(buf, group_profile, check,
                                           prev_knockout_profile, ctx->memory, pgs,
                                           dev, false);
            }
            memcpy(buf->backdrop, buf->data, buf->planestride * buf->n_chan);
        }
#if RAW_DUMP
        /* Dump the current buffer to see what we have. */
        dump_raw_buffer(ctx->stack->rect.q.y-ctx->stack->rect.p.y,
                    ctx->stack->rowstride, buf->n_chan,
                    ctx->stack->planestride, ctx->stack->rowstride,
                    "KnockoutBackDrop", buf->backdrop);
        global_index++;
#endif
    } else {
        buf->backdrop = NULL;
    }
#if RAW_DUMP
    /* Dump the current buffer to see what we have. */
    dump_raw_buffer(ctx->stack->rect.q.y-ctx->stack->rect.p.y,
                ctx->stack->rowstride, ctx->stack->n_planes,
                ctx->stack->planestride, ctx->stack->rowstride,
                "TransGroupPush", ctx->stack->data);
    global_index++;
#endif
    return 0;
}


gs_main_finit(gs_main_instance * minst, int exit_status, int code)
{
    i_ctx_t *i_ctx_p = minst->i_ctx_p;
    gs_dual_memory_t dmem = {0};
    int exit_code;
    ref error_object;
    char *tempnames;

    /* NB: need to free gs_name_table
     */

    /*
     * Previous versions of this code closed the devices in the
     * device list here.  Since these devices are now prototypes,
     * they cannot be opened, so they do not need to be closed;
     * alloc_restore_all will close dynamically allocated devices.
     */
    tempnames = gs_main_tempnames(minst);

    /* by the time we get here, we *must* avoid any random redefinitions of
     * operators etc, so we push systemdict onto the top of the dict stack.
     * We do this in C to avoid running into any other re-defininitions in the
     * Postscript world.
     */
    gs_finit_push_systemdict(i_ctx_p);

    /* We have to disable BGPrint before we call interp_reclaim() to prevent the
     * parent rendering thread initialising for the next page, whilst we are
     * removing objects it may want to access - for example, the I/O device table.
     * We also have to mess with the BeginPage/EndPage procs so that we don't
     * trigger a spurious extra page to be emitted.
     */
    if (minst->init_done >= 2) {
        gs_main_run_string(minst,
            "/BGPrint /GetDeviceParam .special_op \
            {{ <</BeginPage {pop} /EndPage {pop pop //false } \
              /BGPrint false /NumRenderingThreads 0>> setpagedevice} if} if \
              serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse \
              .systemvar exec",
            0 , &exit_code, &error_object);
    }

    /*
     * Close the "main" device, because it may need to write out
     * data before destruction. pdfwrite needs so.
     */
    if (minst->init_done >= 2) {
        int code = 0;

        if (idmemory->reclaim != 0) {
            code = interp_reclaim(&minst->i_ctx_p, avm_global);

            if (code < 0) {
                ref error_name;
                if (tempnames)
                    free(tempnames);

                if (gs_errorname(i_ctx_p, code, &error_name) >= 0) {
                    char err_str[32] = {0};
                    name_string_ref(imemory, &error_name, &error_name);
                    memcpy(err_str, error_name.value.const_bytes, r_size(&error_name));
                    emprintf2(imemory, "ERROR: %s (%d) reclaiming the memory while the interpreter finalization.\n", err_str, code);
                }
                else {
                    emprintf1(imemory, "UNKNOWN ERROR %d reclaiming the memory while the interpreter finalization.\n", code);
                }
#ifdef MEMENTO_SQUEEZE_BUILD
                if (code != gs_error_VMerror ) return gs_error_Fatal;
#else
                return gs_error_Fatal;
#endif
            }
            i_ctx_p = minst->i_ctx_p; /* interp_reclaim could change it. */
        }

        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL &&
            gx_device_is_null(i_ctx_p->pgs->device)) {
            /* if the job replaced the device with the nulldevice, we we need to grestore
               away that device, so the block below can properly dispense
               with the default device.
             */
            int code = gs_grestoreall(i_ctx_p->pgs);
            if (code < 0) return_error(gs_error_Fatal);
        }

        if (i_ctx_p->pgs != NULL && i_ctx_p->pgs->device != NULL) {
            gx_device *pdev = i_ctx_p->pgs->device;
            const char * dname = pdev->dname;

            /* make sure device doesn't isn't freed by .uninstalldevice */
            rc_adjust(pdev, 1, "gs_main_finit");
            /* deactivate the device just before we close it for the last time */
            gs_main_run_string(minst,
                /* we need to do the 'quit' so we don't loop for input (double quit) */
                ".uninstallpagedevice serverdict \
                /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemvar exec",
                0 , &exit_code, &error_object);
            code = gs_closedevice(pdev);
            if (code < 0) {
                ref error_name;
                if (gs_errorname(i_ctx_p, code, &error_name) >= 0) {
                    char err_str[32] = {0};
                    name_string_ref(imemory, &error_name, &error_name);
                    memcpy(err_str, error_name.value.const_bytes, r_size(&error_name));
                    emprintf3(imemory, "ERROR: %s (%d) on closing %s device.\n", err_str, code, dname);
                }
                else {
                    emprintf2(imemory, "UNKNOWN ERROR %d closing %s device.\n", code, dname);
               }
            }
            rc_decrement(pdev, "gs_main_finit");                /* device might be freed */
            if (exit_status == 0 || exit_status == gs_error_Quit)
                exit_status = code;
        }

      /* Flush stdout and stderr */
      gs_main_run_string(minst,
        "(%stdout) (w) file closefile (%stderr) (w) file closefile \
        serverdict /.jobsavelevel get 0 eq {/quit} {/stop} ifelse .systemexec \
          systemdict /savedinitialgstate .forceundef",
        0 , &exit_code, &error_object);
    }
    gp_readline_finit(minst->readline_data);
    i_ctx_p = minst->i_ctx_p;		/* get current interp context */
    if (gs_debug_c(':')) {
        print_resource_usage(minst, &gs_imemory, "Final");
        dmprintf1(minst->heap, "%% Exiting instance 0x%p\n", minst);
    }
    /* Do the equivalent of a restore "past the bottom". */
    /* This will release all memory, close all open files, etc. */
    if (minst->init_done >= 1) {
        gs_memory_t *mem_raw = i_ctx_p->memory.current->non_gc_memory;
        i_plugin_holder *h = i_ctx_p->plugin_list;

        dmem = *idmemory;
        code = alloc_restore_all(i_ctx_p);
        if (code < 0)
            emprintf1(mem_raw,
                      "ERROR %d while the final restore. See gs/psi/ierrors.h for code explanation.\n",
                      code);
        i_iodev_finit(&dmem);
        i_plugin_finit(mem_raw, h);
    }

    /* clean up redirected stdout */
    if (minst->heap->gs_lib_ctx->fstdout2
        && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstdout)
        && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstderr)) {
        fclose(minst->heap->gs_lib_ctx->fstdout2);
        minst->heap->gs_lib_ctx->fstdout2 = (FILE *)NULL;
    }

    minst->heap->gs_lib_ctx->stdout_is_redirected = 0;
    minst->heap->gs_lib_ctx->stdout_to_stderr = 0;
    /* remove any temporary files, after ghostscript has closed files */
    if (tempnames) {
        char *p = tempnames;
        while (*p) {
            unlink(p);
            p += strlen(p) + 1;
        }
        free(tempnames);
    }
    gs_lib_finit(exit_status, code, minst->heap);

    gs_free_object(minst->heap, minst->lib_path.container.value.refs, "lib_path array");
    ialloc_finit(&dmem);
    return exit_status;
}


gx_default_composite_adjust_ctm(gs_composite_t *pcte, int x0, int y0, gs_gstate *pgs)
{
    return 0;
}


gx_default_end_page(gx_device * dev, int reason, gs_gstate * pgs)
{
    return (reason != 2 ? 1 : 0);
}


int epo_fill_linear_color_trapezoid(gx_device *dev, const gs_fill_attributes *fa,
        const gs_fixed_point *p0, const gs_fixed_point *p1,
        const gs_fixed_point *p2, const gs_fixed_point *p3,
        const frac31 *c0, const frac31 *c1,
        const frac31 *c2, const frac31 *c3)
{
    int code = epo_handle_erase_page(dev);

    if (code != 0)
        return code;
    return dev_proc(dev, fill_linear_color_trapezoid)(dev, fa, p0, p1, p2, p3, c0, c1, c2, c3);
}


gx_default_fill_rectangle_hl_color(gx_device *pdev,
    const gs_fixed_rect *rect,
    const gs_gstate *pgs, const gx_drawing_color *pdcolor,
    const gx_clip_path *pcpath)
{
    return_error(gs_error_rangecheck);
}


int epo_copy_alpha(gx_device *dev, const byte *data, int data_x,
    int raster, gx_bitmap_id id, int x, int y, int width, int height,
    gx_color_index color, int depth)
{
    int code = epo_handle_erase_page(dev);

    if (code != 0)
        return code;
    return dev_proc(dev, copy_alpha)(dev, data, data_x, raster, id, x, y, width, height, color, depth);
}


static int chap_gen_challenge(
	struct iscsi_conn *conn,
	int caller,
	char *c_str,
	unsigned int *c_len)
{
	int ret;
	unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
	struct iscsi_chap *chap = conn->auth_protocol;

	memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);

	ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH);
	if (unlikely(ret))
		return ret;
	bin2hex(challenge_asciihex, chap->challenge,
				CHAP_CHALLENGE_LENGTH);
	/*
	 * Set CHAP_C, and copy the generated challenge into c_str.
	 */
	*c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
	*c_len += 1;

	pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
			challenge_asciihex);
	return 0;
}


advance_char (GMarkupParseContext *context)
{
  context->iter++;
  context->char_number++;

  if (G_UNLIKELY (context->iter == context->current_text_end))
      return FALSE;

  else if (G_UNLIKELY (*context->iter == '\n'))
    {
      context->line_number++;
      context->char_number = 1;
    }

  return TRUE;
}


name_validate (GMarkupParseContext  *context,
               const gchar          *name,
               GError              **error)
{
  char mask;
  const char *p;

  /* name start char */
  p = name;
  if (G_UNLIKELY (IS_COMMON_NAME_END_CHAR (*p) ||
                  !(g_ascii_isalpha (*p) || *p == '_' || *p == ':')))
    goto slow_validate;

  for (mask = *p++; *p != '\0'; p++)
    {
      mask |= *p;

      /* is_name_char */
      if (G_UNLIKELY (!(g_ascii_isalnum (*p) ||
                        (!IS_COMMON_NAME_END_CHAR (*p) &&
                         (*p == '.' ||
                          *p == '-' ||
                          *p == '_' ||
                          *p == ':')))))
        goto slow_validate;
    }

  if (mask & 0x80) /* un-common / non-ascii */
    goto slow_validate;

  return TRUE;

 slow_validate:
  return slow_name_validate (context, name, error);
}


push_partial_as_tag (GMarkupParseContext *context)
{
  GString *str = context->partial_chunk;
  /* sadly, this is exported by gmarkup_get_element_stack as-is */
  context->tag_stack = g_slist_concat (get_list_node (context, str->str), context->tag_stack);
  context->tag_stack_gstr = g_slist_concat (get_list_node (context, str), context->tag_stack_gstr);
  context->partial_chunk = NULL;
}


g_markup_parse_context_get_element_stack (GMarkupParseContext *context)
{
  g_return_val_if_fail (context != NULL, NULL);
  return context->tag_stack;
}


g_markup_parse_context_get_element (GMarkupParseContext *context)
{
  g_return_val_if_fail (context != NULL, NULL);

  if (context->tag_stack == NULL)
    return NULL;
  else
    return current_element (context);
}


append_escaped_text (GString     *str,
                     const gchar *text,
                     gssize       length)
{
  const gchar *p;
  const gchar *end;
  gunichar c;

  p = text;
  end = text + length;

  while (p < end)
    {
      const gchar *next;
      next = g_utf8_next_char (p);

      switch (*p)
        {
        case '&':
          g_string_append (str, "&");
          break;

        case '<':
          g_string_append (str, "<");
          break;

        case '>':
          g_string_append (str, ">");
          break;

        case '\'':
          g_string_append (str, "'");
          break;

        case '"':
          g_string_append (str, """);
          break;

        default:
          c = g_utf8_get_char (p);
          if ((0x1 <= c && c <= 0x8) ||
              (0xb <= c && c  <= 0xc) ||
              (0xe <= c && c <= 0x1f) ||
              (0x7f <= c && c <= 0x84) ||
              (0x86 <= c && c <= 0x9f))
            g_string_append_printf (str, "&#x%x;", c);
          else
            g_string_append_len (str, p, next - p);
          break;
        }

      p = next;
    }
}


clear_attributes (GMarkupParseContext *context)
{
  /* Go ahead and free the attributes. */
  for (; context->cur_attr >= 0; context->cur_attr--)
    {
      int pos = context->cur_attr;
      release_chunk (context, context->attr_names[pos]);
      release_chunk (context, context->attr_values[pos]);
      context->attr_names[pos] = context->attr_values[pos] = NULL;
    }
  g_assert (context->cur_attr == -1);
  g_assert (context->attr_names == NULL ||
            context->attr_names[0] == NULL);
  g_assert (context->attr_values == NULL ||
            context->attr_values[0] == NULL);
}


current_element (GMarkupParseContext *context)
{
  return context->tag_stack->data;
}


Magick_png_read_raw_profile(png_struct *ping,Image *image,
   const ImageInfo *image_info, png_textp text,int ii)
{
  register ssize_t
    i;

  register unsigned char
    *dp;

  register png_charp
    sp;

  size_t
    extent,
    length,
    nibbles;

  StringInfo
    *profile;

  static const unsigned char
    unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
                 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
                 0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
                 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
                 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
                 13,14,15};

  sp=text[ii].text+1;
  extent=text[ii].text_length;
  /* look for newline */
  while ((*sp != '\n') && extent--)
    sp++;

  /* look for length */
  while (((*sp == '\0' || *sp == ' ' || *sp == '\n')) && extent--)
     sp++;

  if (extent == 0)
    {
      png_warning(ping,"missing profile length");
      return(MagickFalse);
    }

  length=StringToLong(sp);

  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "      length: %lu",(unsigned long) length);

  while ((*sp != ' ' && *sp != '\n') && extent--)
     sp++;

  if (extent == 0)
    {
      png_warning(ping,"invalid profile length");
      return(MagickFalse);
    }

  /* allocate space */
  if (length == 0)
  {
    png_warning(ping,"invalid profile length");
    return(MagickFalse);
  }

  profile=BlobToStringInfo((const void *) NULL,length);

  if (profile == (StringInfo *) NULL)
  {
    png_warning(ping, "unable to copy profile");
    return(MagickFalse);
  }

  /* copy profile, skipping white space and column 1 "=" signs */
  dp=GetStringInfoDatum(profile);
  nibbles=length*2;

  for (i=0; i < (ssize_t) nibbles; i++)
  {
    while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
    {
      if (*sp == '\0')
        {
          png_warning(ping, "ran out of profile data");
          return(MagickFalse);
        }
      sp++;
    }

    if (i%2 == 0)
      *dp=(unsigned char) (16*unhex[(int) *sp++]);

    else
      (*dp++)+=unhex[(int) *sp++];
  }
  /*
    We have already read "Raw profile type.
  */
  (void) SetImageProfile(image,&text[ii].key[17],profile);
  profile=DestroyStringInfo(profile);

  if (image_info->verbose)
    (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]);

  return MagickTrue;
}