Commit message: None
CVE: CVE-2016-10218
CWE: CWE-476
Vulnerability description: The pdf14_pop_transparency_group function in base/gdevp14.c in the PDF Transparency module in Artifex Software, Inc. Ghostscript 9.20 allows remote attackers to cause a denial of service (NULL pointer dereference and application crash) via a crafted file.

Project: ghostscript
File: gdevp14.c

c_pdf14trans_adjust_ctm(gs_composite_t * pct0, int x0, int y0, gs_gstate *pgs)
{
    gs_pdf14trans_t *pct = (gs_pdf14trans_t *)pct0;
    gs_matrix mat = pct->params.ctm;

    if_debug6m('L', pgs->memory, " [%g %g %g %g %g %g]\n",
               mat.xx, mat.xy, mat.yx, mat.yy,
               mat.tx, mat.ty);
    mat.tx -= x0;
    mat.ty -= y0;
    gs_gstate_setmatrix(pgs, &mat);
    return 0;
}

Project: ghostscript
File: gdevp14.c

gs_pdf14_device_push(gs_memory_t *mem, gs_gstate * pgs,
        gx_device ** pdev, gx_device * target, const gs_pdf14trans_t * pdf14pct)
{
    pdf14_device * dev_proto;
    pdf14_device * p14dev, temp_dev_proto;
    int code;
    bool has_tags;
    cmm_profile_t *icc_profile;
    gsicc_rendering_param_t render_cond;
    cmm_dev_profile_t *dev_profile;
    uchar k;
    int max_bitmap;
    bool use_pdf14_accum = false;

    /* Guard against later seg faults, this should not be possible */
    if (target == NULL)
        return gs_throw_code(gs_error_Fatal);

    has_tags = target->graphics_type_tag & GS_DEVICE_ENCODES_TAGS;
    max_bitmap = target->space_params.MaxBitmap == 0 ? MAX_BITMAP :
                                 target->space_params.MaxBitmap;
    /* If the device is not a printer class device, it won't support saved-pages */
    /* and so we may need to make a clist device in order to prevent very large  */
    /* or high resolution pages from having allocation problems.                 */
    /* We use MaxBitmap to decide when a clist is needed.*/
    if (dev_proc(target, dev_spec_op)(target, gxdso_supports_saved_pages, NULL, 0) == 0 &&
        gx_device_is_pattern_clist(target) == 0 &&
        gx_device_is_pattern_accum(target) == 0 &&
        gs_device_is_memory(target) == 0) {

        uint32_t pdf14_trans_buffer_size = (ESTIMATED_PDF14_ROW_SPACE(max(1, target->width),
                                             target->color_info.num_components) >> 3);

        if (target->height < max_ulong / pdf14_trans_buffer_size)
                pdf14_trans_buffer_size *= target->height;
        else
                max_bitmap = 0;     /* Force decision to clist */
        if (pdf14_trans_buffer_size > max_bitmap)
            use_pdf14_accum = true;
    }
    code = dev_proc(target, get_profile)(target,  &dev_profile);
    if (code < 0)
        return code;
    gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, &icc_profile,
                          &render_cond);
    if_debug0m('v', mem, "[v]gs_pdf14_device_push\n");

    code = get_pdf14_device_proto(target, &dev_proto, &temp_dev_proto, pgs,
                                  pdf14pct, use_pdf14_accum);
    if (code < 0)
        return code;
    code = gs_copydevice((gx_device **) &p14dev,
                         (const gx_device *) dev_proto, mem);
    if (code < 0)
        return code;
    gs_pdf14_device_copy_params((gx_device *)p14dev, target);
    gx_device_set_target((gx_device_forward *)p14dev, target);
    p14dev->pad = target->pad;
    p14dev->log2_align_mod = target->log2_align_mod;
    p14dev->is_planar = target->is_planar;
    /* If the target profile was CIELAB (and we are not using a blend CS),
       then overide with default RGB for
       proper blending.  During put_image we will convert from RGB to
       CIELAB.  Need to check that we have a default profile, which
       will not be the case if we are coming from the clist reader */
    if ((icc_profile->data_cs == gsCIELAB || icc_profile->islab)
        && pgs->icc_manager->default_rgb != NULL && !p14dev->using_blend_cs) {
        p14dev->icc_struct->device_profile[0] =
                                        pgs->icc_manager->default_rgb;
        rc_increment(pgs->icc_manager->default_rgb);
    }
    /* The number of color planes should not exceed that of the target.
       Unless we are using a blend CS */
    if (!p14dev->using_blend_cs) {
        if (p14dev->color_info.num_components > target->color_info.num_components)
            p14dev->color_info.num_components = target->color_info.num_components;
        if (p14dev->color_info.max_components > target->color_info.max_components)
            p14dev->color_info.max_components = target->color_info.max_components;
    }
    p14dev->color_info.depth = p14dev->color_info.num_components * 8;
    /* If we have a tag device then go ahead and do a special encoder
       decoder for the pdf14 device to make sure we maintain this
       information in the encoded color information.  We could use
       the target device's methods but the PDF14 device has to maintain
       8 bit color always and we could run into other issues if the number
       of colorants became large.  If we need to do compressed color with
       tags that will be a special project at that time */
    if (has_tags) {
        p14dev->procs.encode_color = pdf14_encode_color_tag;
        p14dev->color_info.depth += 8;
    }
    check_device_separable((gx_device *)p14dev);
    gx_device_fill_in_procs((gx_device *)p14dev);
    p14dev->save_get_cmap_procs = pgs->get_cmap_procs;
    pgs->get_cmap_procs = pdf14_get_cmap_procs;
    gx_set_cmap_procs(pgs, (gx_device *)p14dev);
    /* Components shift, etc have to be based upon 8 bit */
    for (k = 0; k < p14dev->color_info.num_components; k++) {
        p14dev->color_info.comp_bits[k] = 8;
        p14dev->color_info.comp_shift[k] =
                            (p14dev->color_info.num_components - 1 - k) * 8;
    }
    if (use_pdf14_accum) {
        /* we will disable this device later, but we don't want to allocate large buffers */
        p14dev->width = 1;
        p14dev->height = 1;
    }
    code = dev_proc((gx_device *) p14dev, open_device) ((gx_device *) p14dev);
    *pdev = (gx_device *) p14dev;
    pdf14_set_marking_params((gx_device *)p14dev, pgs);
    p14dev->trans_group_parent_cmap_procs = NULL;
    /* In case we have alphabits set */
    p14dev->color_info.anti_alias = target->color_info.anti_alias;
#if RAW_DUMP
    /* Dump the current buffer to see what we have. */
    dump_raw_buffer(p14dev->ctx->stack->rect.q.y-p14dev->ctx->stack->rect.p.y,
                p14dev->ctx->stack->rect.q.x-p14dev->ctx->stack->rect.p.x,
                                p14dev->ctx->stack->n_planes,
                p14dev->ctx->stack->planestride, p14dev->ctx->stack->rowstride,
                "Device_Push",p14dev->ctx->stack->data);

    global_index++;
#endif
    /* We should never go into this when using a blend color space */
    if (use_pdf14_accum) {
        const gx_device_pdf14_accum *accum_proto = NULL;
        gx_device *new_target = NULL;
        gx_device_color pdcolor;
        frac pconc_white = frac_1;

        if_debug0m('v', mem, "[v]gs_pdf14_device_push: Inserting clist device.\n");

        /* get the prototype for the accumulator device based on colorspace */
        switch (target->color_info.num_components) {
            case 1:
                accum_proto = &pdf14_accum_Gray;
                break;
            case 3:
                accum_proto = &pdf14_accum_RGB;
                break;
            case 4:
                accum_proto = &pdf14_accum_CMYK;
                break;
            default:
                /* FIXME: DeviceN ?? */
                break;		/* accum_proto will be NULL, so no accum device */
        }
        if (accum_proto == NULL ||
            (code = gs_copydevice(&new_target, (gx_device *)accum_proto, mem->stable_memory)) < 0)
            goto no_clist_accum;

        ((gx_device_pdf14_accum *)new_target)->save_p14dev = (gx_device *)p14dev;  /* non-clist p14dev */
        /* Fill in values from the target device before opening */
        new_target->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
        new_target->color_info.anti_alias = p14dev->color_info.anti_alias;
        set_linear_color_bits_mask_shift(new_target);
        gs_pdf14_device_copy_params(new_target, target);
        ((gx_device_pdf14_accum *)new_target)->page_uses_transparency = true;
        gx_device_fill_in_procs(new_target);

        memcpy(&(new_target->space_params), &(target->space_params), sizeof(gdev_space_params));
        max_bitmap = max(target->space_params.MaxBitmap, target->space_params.BufferSpace);
        new_target->space_params.BufferSpace = max_bitmap;

        new_target->PageHandlerPushed = true;
        new_target->ObjectHandlerPushed = true;

        if ((code = gdev_prn_open(new_target)) < 0 ||
             !PRINTER_IS_CLIST((gx_device_printer *)new_target)) {
            gs_free_object(mem->stable_memory, new_target, "pdf14-accum");
            goto no_clist_accum;
        }
        /* Do the initial fillpage into the pdf14-accum device we just created */
        dev_proc(new_target, set_graphics_type_tag)(new_target, GS_PATH_TAG);
        if ((code = gx_remap_concrete_DGray(&pconc_white,
                                            gs_currentcolorspace_inline((gs_gstate *)pgs),
                                            &pdcolor, pgs, new_target, gs_color_select_all)) < 0)
            goto no_clist_accum;

        (*dev_proc(new_target, fillpage))(new_target, pgs, &pdcolor);
        code = clist_create_compositor(new_target, pdev, (gs_composite_t *)pdf14pct, pgs, mem, NULL);
        if (code < 0)
            goto no_clist_accum;

        pdf14_disable_device((gx_device *)p14dev);           /* make the non-clist device forward */
        pdf14_close((gx_device *)p14dev);                    /* and free up the little memory it had */
    }
    return code;

no_clist_accum:
        /* FIXME: We allocated a really small p14dev, but that won't work */
    return gs_throw_code(gs_error_Fatal); /* punt for now */
}

Project: ghostscript
File: gdevp14.c

pdf14_buf_new(gs_int_rect *rect, bool has_tags, bool has_alpha_g,
              bool has_shape, bool idle, int n_chan, int num_spots,
              gs_memory_t *memory)
{

        /* Note that alpha_g is the alpha for the GROUP */
        /* This is distinct from the alpha that may also exist */
        /* for the objects within the group.  Hence it can introduce */
        /* yet another plane */

    pdf14_buf *result;
    pdf14_parent_color_t *new_parent_color;
    int rowstride = (rect->q.x - rect->p.x + 3) & -4;
    int height = (rect->q.y - rect->p.y);
    int n_planes = n_chan + (has_shape ? 1 : 0) + (has_alpha_g ? 1 : 0) +
                   (has_tags ? 1 : 0);
    int planestride;
    double dsize = (((double) rowstride) * height) * n_planes;

    if (dsize > (double)max_uint)
      return NULL;

    result = gs_alloc_struct(memory, pdf14_buf, &st_pdf14_buf,
                             "pdf14_buf_new");
    if (result == NULL)
        return result;

    result->backdrop = NULL;
    result->saved = NULL;
    result->isolated = false;
    result->knockout = false;
    result->has_alpha_g = has_alpha_g;
    result->has_shape = has_shape;
    result->has_tags = has_tags;
    result->rect = *rect;
    result->n_chan = n_chan;
    result->n_planes = n_planes;
    result->rowstride = rowstride;
    result->transfer_fn = NULL;
    result->matte_num_comps = 0;
    result->matte = NULL;
    result->mask_stack = NULL;
    result->idle = idle;
    result->mask_id = 0;
    result->num_spots = num_spots;
    new_parent_color = gs_alloc_struct(memory, pdf14_parent_color_t, &st_pdf14_clr,
                                                "pdf14_buf_new");
    if (new_parent_color == NULL) {
        gs_free_object(memory, result, "pdf14_buf_new");
        return NULL;
    }

    result->parent_color_info_procs = new_parent_color;
    result->parent_color_info_procs->get_cmap_procs = NULL;
    result->parent_color_info_procs->parent_color_mapping_procs = NULL;
    result->parent_color_info_procs->parent_color_comp_index = NULL;
    result->parent_color_info_procs->icc_profile = NULL;
    result->parent_color_info_procs->previous = NULL;
    result->parent_color_info_procs->encode = NULL;
    result->parent_color_info_procs->decode = NULL;
    if (height <= 0) {
        /* Empty clipping - will skip all drawings. */
        result->planestride = 0;
        result->data = 0;
    } else {
        planestride = rowstride * height;
        result->planestride = planestride;
        result->data = gs_alloc_bytes(memory, planestride * n_planes,
                                        "pdf14_buf_new");
        if (result->data == NULL) {
            gs_free_object(memory, result, "pdf14_buf_new");
            return NULL;
        }
        if (has_alpha_g) {
            int alpha_g_plane = n_chan + (has_shape ? 1 : 0);
            memset (result->data + alpha_g_plane * planestride, 0, planestride);
        }
        if (has_tags) {
            int tags_plane = n_chan + (has_shape ? 1 : 0) + (has_alpha_g ? 1 : 0);
            memset (result->data + tags_plane * planestride,
                    GS_UNTOUCHED_TAG, planestride);
        }
    }
    /* Initialize dirty box with an invalid rectangle (the reversed rectangle).
     * Any future drawing will make it valid again, so we won't blend back
     * more than we need. */
    result->dirty.p.x = rect->q.x;
    result->dirty.p.y = rect->q.y;
    result->dirty.q.x = rect->p.x;
    result->dirty.q.y = rect->p.y;
    return result;
}

Project: ghostscript
File: gdevp14.c

pdf14_clist_forward_create_compositor(gx_device	* dev, gx_device * * pcdev,
        const gs_composite_t * pct, gs_gstate * pgs,
        gs_memory_t * mem, gx_device *cdev)
{
    pdf14_device *pdev = (pdf14_device *)dev;
    gx_device * tdev = pdev->target;
    gx_device * ndev;
    int code;

    *pcdev = dev;
    if (gs_is_pdf14trans_compositor(pct)) {
        const gs_pdf14trans_t * pdf14pct = (const gs_pdf14trans_t *) pct;

        if (pdf14pct->params.pdf14_op == PDF14_PUSH_DEVICE)
            return pdf14_clist_create_compositor(dev, &ndev, pct, pgs, mem, cdev);
        return 0;
    }
    code = dev_proc(tdev, create_compositor)(tdev, &ndev, pct, pgs, mem, cdev);
    if (code < 0)
        return code;
    gx_device_set_target((gx_device_forward *)pdev, ndev);
    return 0;
}

Project: ghostscript
File: gdevp14.c

pdf14_clist_text_begin(gx_device * dev,	gs_gstate	* pgs,
                 const gs_text_params_t * text, gs_font * font,
                 gx_path * path, const gx_device_color * pdcolor,
                 const gx_clip_path * pcpath, gs_memory_t * memory,
                 gs_text_enum_t ** ppenum)
{
    pdf14_clist_device * pdev = (pdf14_clist_device *)dev;
    gs_text_enum_t *penum;
    int code;

    if_debug0m('v', memory, "[v]pdf14_clist_text_begin\n");
    /*
     * Ensure that that the PDF 1.4 reading compositor will have the current
     * blending parameters.  This is needed since the fill_rectangle routines
     * do not have access to the gs_gstate.  Thus we have to pass any
     * changes explictly.
     */
    code = pdf14_clist_update_params(pdev, pgs, false, NULL);
    if (code < 0)
        return code;
    /* Pass text_begin to the target */
    code = gx_forward_text_begin(dev, pgs, text, font, path,
                                pdcolor, pcpath, memory, &penum);
    if (code < 0)
        return code;
    *ppenum = (gs_text_enum_t *)penum;
    return code;
}

Project: ghostscript
File: gdevp14.c

pdf14_clist_update_params(pdf14_clist_device * pdev, const gs_gstate * pgs,
                          bool crop_blend_params,
                          gs_pdf14trans_params_t *group_params)
{
    gs_pdf14trans_params_t params = { 0 };
    gx_device * pcdev;
    int changed = 0;
    int code = 0;
    gs_composite_t *pct_new = NULL;

    params.crop_blend_params = crop_blend_params;

    params.pdf14_op = PDF14_SET_BLEND_PARAMS;
    if (pgs->blend_mode != pdev->blend_mode) {
        changed |= PDF14_SET_BLEND_MODE;
        params.blend_mode = pdev->blend_mode = pgs->blend_mode;
    }
    if (pgs->text_knockout != pdev->text_knockout) {
        changed |= PDF14_SET_TEXT_KNOCKOUT;
        params.text_knockout = pdev->text_knockout = pgs->text_knockout;
    }
    if (pgs->shape.alpha != pdev->shape) {
        changed |= PDF14_SET_SHAPE_ALPHA;
        params.shape.alpha = pdev->shape = pgs->shape.alpha;
    }
    if (pgs->opacity.alpha != pdev->opacity) {
        changed |= PDF14_SET_OPACITY_ALPHA;
        params.opacity.alpha = pdev->opacity = pgs->opacity.alpha;
    }
    if (pgs->overprint != pdev->overprint) {
        changed |= PDF14_SET_OVERPRINT;
        params.overprint = pdev->overprint = pgs->overprint;
    }
    if (pgs->overprint_mode != pdev->overprint_mode) {
        changed |= PDF14_SET_OVERPRINT_MODE;
        params.overprint_mode = pdev->overprint_mode = pgs->overprint_mode;
    }
    if (crop_blend_params) {
        params.ctm = group_params->ctm;
        params.bbox = group_params->bbox;
    }
    params.changed = changed;
    /* Avoid recursion when we have a PDF14_SET_BLEND_PARAMS forced and apply
       now to the target.  Otherwise we send of te compositor action
       to the pdf14 device at this time.  This is due to the fact that we
       need to often perform this operation when we are already starting to
       do a compositor action */
    if (changed != 0) {
        code = gs_create_pdf14trans(&pct_new, &params, pgs->memory);
        if (code < 0) return code;
        code = dev_proc(pdev->target, create_compositor)
                    (pdev->target, &pcdev, pct_new, (gs_gstate *)pgs, pgs->memory, NULL);
        gs_free_object(pgs->memory, pct_new, "pdf14_clist_update_params");
    }
    return code;
}

Project: ghostscript
File: gdevp14.c

pdf14_cmap_rgb_alpha_direct(frac r, frac g, frac b, frac alpha,	gx_device_color	* pdc,
     const gs_gstate * pgs, gx_device * dev, gs_color_select_t select)
{
    int i, ncomps;
    frac cm_comps[GX_DEVICE_COLOR_MAX_COMPONENTS];
    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
    gx_color_index color;
    gx_device *trans_device;

     /*  We may be coming from the clist writer which often forwards us the
         target device. If this occurs we actually need to get to the color
         space defined by the transparency group and we use the operators
         defined by the transparency device to do the job. */
    if (pgs->trans_device != NULL){
        trans_device = pgs->trans_device;
    } else {
        trans_device = dev;
    }
    ncomps = trans_device->color_info.num_components;
    /* map to the color model */
    dev_proc(trans_device, get_color_mapping_procs)(trans_device)->map_rgb(trans_device, pgs, r, g, b, cm_comps);
    /* pre-multiply to account for the alpha weighting */
    if (alpha != frac_1) {
#ifdef PREMULTIPLY_TOWARDS_WHITE
        frac alpha_bias = frac_1 - alpha;
#else
        frac alpha_bias = 0;
#endif
        for (i = 0; i < ncomps; i++)
            cm_comps[i] = (frac)((long)cm_comps[i] * alpha) / frac_1 + alpha_bias;
    }

    for (i = 0; i < ncomps; i++)
        cv[i] = frac2cv(gx_map_color_frac(pgs, cm_comps[i], effective_transfer[i]));
    color = dev_proc(trans_device, encode_color)(trans_device, cv);
    /* check if the encoding was successful; we presume failure is rare */
    if (color != gx_no_color_index)
        color_set_pure(pdc, color);
}

Project: ghostscript
File: gdevp14.c

pdf14_copy_alpha_color(gx_device * dev, const byte * data, int data_x,
           int aa_raster, gx_bitmap_id id, int x, int y, int w, int h,
                      gx_color_index color, const gx_device_color *pdc,
                      int depth, bool devn)
{
    const byte *aa_row;
    pdf14_device *pdev = (pdf14_device *)dev;
    pdf14_buf *buf = pdev->ctx->stack;
    int i, j, k;
    byte *line, *dst_ptr;
    byte src[PDF14_MAX_PLANES];
    byte dst[PDF14_MAX_PLANES] = { 0 };
    gs_blend_mode_t blend_mode = pdev->blend_mode;
    bool additive = pdev->ctx->additive;
    int rowstride = buf->rowstride;
    int planestride = buf->planestride;
    gs_graphics_type_tag_t curr_tag = GS_UNKNOWN_TAG;  /* Quiet compiler */
    bool has_alpha_g = buf->has_alpha_g;
    bool has_shape = buf->has_shape;
    bool has_tags = buf->has_tags;
    bool knockout = buf->knockout;
    int num_chan = buf->n_chan;
    int num_comp = num_chan - 1;
    int shape_off = num_chan * planestride;
    int alpha_g_off = shape_off + (has_shape ? planestride : 0);
    int tag_off = alpha_g_off + (has_alpha_g ? planestride : 0);
    bool overprint = pdev->overprint;
    gx_color_index drawn_comps = pdev->drawn_comps;
    gx_color_index comps;
    byte shape = 0; /* Quiet compiler. */
    byte src_alpha;
    int alpha2_aa, alpha_aa, sx;
    int alpha_aa_act;
    int xoff;
    gx_color_index mask = ((gx_color_index)1 << 8) - 1;
    int shift = 8;

    if (buf->data == NULL)
        return 0;
    aa_row = data;
    if (has_tags) {
        curr_tag = (color >> (num_comp*8)) & 0xff;
    }

    if (devn) {
        if (additive) {
            for (j = 0; j < num_comp; j++) {
                src[j] = ((pdc->colors.devn.values[j]) >> shift & mask);
            }
        } else {
            for (j = 0; j < num_comp; j++) {
                src[j] = 255 - ((pdc->colors.devn.values[j]) >> shift & mask);
            }
        }
    } else
        pdev->pdf14_procs->unpack_color(num_comp, color, pdev, src);
    src_alpha = src[num_comp] = (byte)floor (255 * pdev->alpha + 0.5);
    if (has_shape)
        shape = (byte)floor (255 * pdev->shape + 0.5);
    /* Limit the area we write to the bounding rectangle for this buffer */
    if (x < buf->rect.p.x) {
        xoff = data_x + buf->rect.p.x - x;
        w += x - buf->rect.p.x;
        x = buf->rect.p.x;
    } else {
        xoff = data_x;
    }
    if (y < buf->rect.p.y) {
      h += y - buf->rect.p.y;
      aa_row -= (y - buf->rect.p.y) * aa_raster;
      y = buf->rect.p.y;
    }
    if (x + w > buf->rect.q.x) w = buf->rect.q.x - x;
    if (y + h > buf->rect.q.y) h = buf->rect.q.y - y;
    /* Update the dirty rectangle. */
    if (x < buf->dirty.p.x) buf->dirty.p.x = x;
    if (y < buf->dirty.p.y) buf->dirty.p.y = y;
    if (x + w > buf->dirty.q.x) buf->dirty.q.x = x + w;
    if (y + h > buf->dirty.q.y) buf->dirty.q.y = y + h;
    line = buf->data + (x - buf->rect.p.x) + (y - buf->rect.p.y) * rowstride;

    for (j = 0; j < h; ++j, aa_row += aa_raster) {
        dst_ptr = line;
        sx = xoff;
        for (i = 0; i < w; ++i, ++sx) {
            /* Complement the components for subtractive color spaces */
            if (additive) {
                for (k = 0; k < num_chan; ++k)		/* num_chan includes alpha */
                    dst[k] = dst_ptr[k * planestride];
            } else { /* Complement the components for subtractive color spaces */
                for (k = 0; k < num_comp; ++k)
                    dst[k] = 255 - dst_ptr[k * planestride];
                dst[num_comp] = dst_ptr[num_comp * planestride];	/* alpha */
            }
            /* Get the aa alpha from the buffer */
            switch(depth)
            {
            case 2:  /* map 0 - 3 to 0 - 255 */
                alpha_aa = ((aa_row[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 85;
                break;
            case 4:
                alpha2_aa = aa_row[sx >> 1];
                alpha_aa = (sx & 1 ? alpha2_aa & 0xf : alpha2_aa >> 4) * 17;
                break;
            case 8:
                alpha_aa = aa_row[sx];
                break;
            default:
                return_error(gs_error_rangecheck);
            }
            if (alpha_aa != 0) {  /* This does happen */
                if (alpha_aa != 255) {
                    /* We have an alpha value from aa */
                    alpha_aa_act = alpha_aa;
                    if (src_alpha != 255) {
                        /* Need to combine it with the existing alpha */
                        int tmp = src_alpha * alpha_aa_act + 0x80;
                        alpha_aa_act = (tmp + (tmp >> 8)) >> 8;
                    }
                    /* Set our source alpha value appropriately */
                    src[num_comp] = alpha_aa_act;
                } else {
                    /* We may have to reset this is it was changed as we
                       moved across the row */
                    src[num_comp] = src_alpha;
                }
                if (knockout) {
                    if (has_shape) {
                        art_pdf_composite_knockout_8(dst, src, num_comp, blend_mode,
                                            pdev->blend_procs, pdev);
                    } else {
                        art_pdf_knockoutisolated_group_aa_8(dst, src, src_alpha,
                                            alpha_aa, num_comp, pdev);
                    }
                } else {
                    art_pdf_composite_pixel_alpha_8(dst, src, num_comp, blend_mode,
                                                    pdev->blend_procs, pdev);
                }
                /* Complement the results for subtractive color spaces */
                if (additive) {
                    for (k = 0; k < num_chan; ++k)
                        dst_ptr[k * planestride] = dst[k];
                } else {
                    if (overprint && dst_ptr[num_comp * planestride] != 0) {
                        for (k = 0, comps = drawn_comps; comps != 0;
                                ++k, comps >>= 1) {
                            if ((comps & 0x1) != 0) {
                                dst_ptr[k * planestride] = 255 - dst[k];
                            }
                        }
                        /* The alpha channel */
                        dst_ptr[num_comp * planestride] = dst[num_comp];
                    } else {
                        for (k = 0; k < num_comp; ++k)
                            dst_ptr[k * planestride] = 255 - dst[k];
                        /* The alpha channel */
                        dst_ptr[num_comp * planestride] = dst[num_comp];
                    }
                }
                if (has_alpha_g) {
                    int tmp = (255 - dst_ptr[alpha_g_off]) * (255 - src[num_comp]) + 0x80;
                    dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
                }
                if (has_shape) {
                    int tmp = (255 - dst_ptr[shape_off]) * (255 - shape) + 0x80;
                    dst_ptr[shape_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
                }
                if (has_tags) {
                    /* If alpha is 100% then set to pure path, else or */
                    if (src[num_comp] == 255) {
                        dst_ptr[tag_off] = curr_tag;
                    } else {
                        dst_ptr[tag_off] = ( dst_ptr[tag_off] |curr_tag ) & ~GS_UNTOUCHED_TAG;
                    }
                }
            }
            ++dst_ptr;
        }
        line += rowstride;
    }
    return 0;
}

Project: ghostscript
File: gdevp14.c

pdf14_debug_mask_stack_state(pdf14_ctx *ctx)
{
    return;
}

Project: ghostscript
File: gdevp14.c

pdf14_dev_spec_op(gx_device *pdev, int dev_spec_op,
                  void *data, int size)
{
    if (dev_spec_op == gxdso_pattern_shfill_doesnt_need_path)
        return 1;
    if (dev_spec_op == gxdso_is_pdf14_device) {
        if (data != NULL && size == sizeof(gx_device *))
            *(gx_device **)data = pdev;
        return 1;
    }
    if (dev_spec_op == gxdso_device_child) {
        pdf14_device *dev = (pdf14_device *)pdev;
        gxdso_device_child_request *d = (gxdso_device_child_request *)data;
        if (d->target == pdev) {
            d->target = dev->target;
            return 1;
        }
    }
    if (dev_spec_op == gxdso_supports_devn) {
        cmm_dev_profile_t *dev_profile;
        int code;
        code = dev_proc(pdev, get_profile)((gx_device*) pdev, &dev_profile);
        if (code == 0) {
            return dev_profile->supports_devn;
        } else {
            return 0;
        }
    }
    return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
}

Project: ghostscript
File: gdevp14.c

pdf14_update_device_color_procs_pop_c(gx_device *dev,gs_gstate *pgs)
{

    pdf14_device *pdev = (pdf14_device *)dev;
    pdf14_parent_color_t *parent_color = pdev->trans_group_parent_cmap_procs;
    gx_device_clist_writer * cldev = (gx_device_clist_writer *)pdev->pclist_device;

    if_debug0m('v', pdev->memory, "[v]pdf14_update_device_color_procs_pop_c\n");
    /* The color procs are always pushed.  Simply restore them. */
    if (!(parent_color->parent_color_mapping_procs == NULL &&
        parent_color->parent_color_comp_index == NULL)) {
        if_debug2m('v', pdev->memory,
                   "[v]pdf14_update_device_color_procs_pop_c,num_components_old = %d num_components_new = %d\n",
                   pdev->color_info.num_components,parent_color->num_components);
        pgs->get_cmap_procs = parent_color->get_cmap_procs;
        gx_set_cmap_procs(pgs, dev);
        pdev->procs.get_color_mapping_procs = parent_color->parent_color_mapping_procs;
        pdev->procs.get_color_comp_index = parent_color->parent_color_comp_index;
        pdev->color_info.polarity = parent_color->polarity;
        pdev->color_info.depth = parent_color->depth;
        pdev->color_info.num_components = parent_color->num_components;
        pdev->blend_procs = parent_color->parent_blending_procs;
        pdev->pdf14_procs = parent_color->unpack_procs;
        pdev->color_info.max_color = parent_color->max_color;
        pdev->color_info.max_gray = parent_color->max_gray;
        pdev->procs.encode_color = parent_color->encode;
        pdev->procs.decode_color = parent_color->decode;
        memcpy(&(pdev->color_info.comp_bits),&(parent_color->comp_bits),
                            GX_DEVICE_COLOR_MAX_COMPONENTS);
        memcpy(&(pdev->color_info.comp_shift),&(parent_color->comp_shift),
                            GX_DEVICE_COLOR_MAX_COMPONENTS);
        /* clist writer fill rect has no access to gs_gstate */
        /* and it forwards the target device.  this information */
        /* is passed along to use in this case */
        cldev->clist_color_info.depth = pdev->color_info.depth;
        cldev->clist_color_info.polarity = pdev->color_info.polarity;
        cldev->clist_color_info.num_components = pdev->color_info.num_components;
        cldev->clist_color_info.max_color = pdev->color_info.max_color;
        cldev->clist_color_info.max_gray = pdev->color_info.max_gray;
        memcpy(&(cldev->clist_color_info.comp_bits),&(parent_color->comp_bits),
                            GX_DEVICE_COLOR_MAX_COMPONENTS);
        memcpy(&(cldev->clist_color_info.comp_shift),&(parent_color->comp_shift),
                            GX_DEVICE_COLOR_MAX_COMPONENTS);
        if (pdev->ctx){
            pdev->ctx->additive = parent_color->isadditive;
        }
       /* The device profile must be restored. */
         dev->icc_struct->device_profile[0] = parent_color->icc_profile;
         rc_decrement(parent_color->icc_profile, "pdf14_update_device_color_procs_pop_c");
         parent_color->icc_profile = NULL;
         if_debug0m('v', dev->memory, "[v]procs updated\n");
    } else {
        if_debug0m('v', dev->memory, "[v]pdf14_update_device_color_procs_pop_c ERROR \n");
    }
    pdf14_pop_parent_color(dev, pgs);
    return 0;
}