13ff48bf5SDavid du Colombier /* Copyright (C) 2000 Aladdin Enterprises. All rights reserved.
23ff48bf5SDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
53ff48bf5SDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gximag3x.c,v 1.20 2004/09/16 08:03:56 igor Exp $ */
183ff48bf5SDavid du Colombier /* ImageType 3x image implementation */
193ff48bf5SDavid du Colombier /****** THE REAL WORK IS NYI ******/
203ff48bf5SDavid du Colombier #include "math_.h" /* for ceil, floor */
213ff48bf5SDavid du Colombier #include "memory_.h"
223ff48bf5SDavid du Colombier #include "gx.h"
233ff48bf5SDavid du Colombier #include "gserrors.h"
243ff48bf5SDavid du Colombier #include "gsbitops.h"
253ff48bf5SDavid du Colombier #include "gscspace.h"
263ff48bf5SDavid du Colombier #include "gscpixel.h"
273ff48bf5SDavid du Colombier #include "gsstruct.h"
283ff48bf5SDavid du Colombier #include "gxdevice.h"
293ff48bf5SDavid du Colombier #include "gxdevmem.h"
303ff48bf5SDavid du Colombier #include "gximag3x.h"
313ff48bf5SDavid du Colombier #include "gxistate.h"
323ff48bf5SDavid du Colombier #include "gdevbbox.h"
333ff48bf5SDavid du Colombier
343ff48bf5SDavid du Colombier extern_st(st_color_space);
353ff48bf5SDavid du Colombier
363ff48bf5SDavid du Colombier /* Forward references */
373ff48bf5SDavid du Colombier private dev_proc_begin_typed_image(gx_begin_image3x);
383ff48bf5SDavid du Colombier private image_enum_proc_plane_data(gx_image3x_plane_data);
393ff48bf5SDavid du Colombier private image_enum_proc_end_image(gx_image3x_end_image);
403ff48bf5SDavid du Colombier private image_enum_proc_flush(gx_image3x_flush);
413ff48bf5SDavid du Colombier private image_enum_proc_planes_wanted(gx_image3x_planes_wanted);
423ff48bf5SDavid du Colombier
433ff48bf5SDavid du Colombier /* GC descriptor */
443ff48bf5SDavid du Colombier private_st_gs_image3x();
453ff48bf5SDavid du Colombier
463ff48bf5SDavid du Colombier /* Define the image type for ImageType 3x images. */
473ff48bf5SDavid du Colombier const gx_image_type_t gs_image_type_3x = {
483ff48bf5SDavid du Colombier &st_gs_image3x, gx_begin_image3x, gx_data_image_source_size,
493ff48bf5SDavid du Colombier gx_image_no_sput, gx_image_no_sget, gx_image_default_release,
503ff48bf5SDavid du Colombier IMAGE3X_IMAGETYPE
513ff48bf5SDavid du Colombier };
523ff48bf5SDavid du Colombier private const gx_image_enum_procs_t image3x_enum_procs = {
533ff48bf5SDavid du Colombier gx_image3x_plane_data, gx_image3x_end_image,
543ff48bf5SDavid du Colombier gx_image3x_flush, gx_image3x_planes_wanted
553ff48bf5SDavid du Colombier };
563ff48bf5SDavid du Colombier
573ff48bf5SDavid du Colombier /* Initialize an ImageType 3x image. */
583ff48bf5SDavid du Colombier private void
gs_image3x_mask_init(gs_image3x_mask_t * pimm)593ff48bf5SDavid du Colombier gs_image3x_mask_init(gs_image3x_mask_t *pimm)
603ff48bf5SDavid du Colombier {
613ff48bf5SDavid du Colombier pimm->InterleaveType = 0; /* not a valid type */
623ff48bf5SDavid du Colombier pimm->has_Matte = false;
633ff48bf5SDavid du Colombier gs_data_image_t_init(&pimm->MaskDict, 1);
643ff48bf5SDavid du Colombier pimm->MaskDict.BitsPerComponent = 0; /* not supplied */
653ff48bf5SDavid du Colombier }
663ff48bf5SDavid du Colombier void
gs_image3x_t_init(gs_image3x_t * pim,const gs_color_space * color_space)673ff48bf5SDavid du Colombier gs_image3x_t_init(gs_image3x_t * pim, const gs_color_space * color_space)
683ff48bf5SDavid du Colombier {
693ff48bf5SDavid du Colombier gs_pixel_image_t_init((gs_pixel_image_t *) pim, color_space);
703ff48bf5SDavid du Colombier pim->type = &gs_image_type_3x;
713ff48bf5SDavid du Colombier gs_image3x_mask_init(&pim->Opacity);
723ff48bf5SDavid du Colombier gs_image3x_mask_init(&pim->Shape);
733ff48bf5SDavid du Colombier }
743ff48bf5SDavid du Colombier
753ff48bf5SDavid du Colombier /*
763ff48bf5SDavid du Colombier * We implement ImageType 3 images by interposing a mask clipper in
773ff48bf5SDavid du Colombier * front of an ordinary ImageType 1 image. Note that we build up the
783ff48bf5SDavid du Colombier * mask row-by-row as we are processing the image.
793ff48bf5SDavid du Colombier *
803ff48bf5SDavid du Colombier * We export a generalized form of the begin_image procedure for use by
813ff48bf5SDavid du Colombier * the PDF and PostScript writers.
823ff48bf5SDavid du Colombier */
833ff48bf5SDavid du Colombier
843ff48bf5SDavid du Colombier typedef struct image3x_channel_state_s {
853ff48bf5SDavid du Colombier gx_image_enum_common_t *info;
863ff48bf5SDavid du Colombier gx_device *mdev; /* gx_device_memory in default impl. */
873ff48bf5SDavid du Colombier /* (only for masks) */
883ff48bf5SDavid du Colombier gs_image3_interleave_type_t InterleaveType;
893ff48bf5SDavid du Colombier int width, height, full_height, depth;
903ff48bf5SDavid du Colombier byte *data; /* (if chunky) */
913ff48bf5SDavid du Colombier /* Only the following change dynamically. */
923ff48bf5SDavid du Colombier int y;
933ff48bf5SDavid du Colombier int skip; /* only for masks, # of rows to skip, */
943ff48bf5SDavid du Colombier /* see below */
953ff48bf5SDavid du Colombier } image3x_channel_state_t;
963ff48bf5SDavid du Colombier typedef struct gx_image3x_enum_s {
973ff48bf5SDavid du Colombier gx_image_enum_common;
983ff48bf5SDavid du Colombier gx_device *pcdev; /* gx_device_mask_clip in default impl. */
993ff48bf5SDavid du Colombier int num_components; /* (not counting masks) */
1003ff48bf5SDavid du Colombier int bpc; /* pixel BitsPerComponent */
1013ff48bf5SDavid du Colombier gs_memory_t *memory;
1023ff48bf5SDavid du Colombier #define NUM_MASKS 2 /* opacity, shape */
1033ff48bf5SDavid du Colombier image3x_channel_state_t mask[NUM_MASKS], pixel;
1043ff48bf5SDavid du Colombier } gx_image3x_enum_t;
1053ff48bf5SDavid du Colombier
1063ff48bf5SDavid du Colombier extern_st(st_gx_image_enum_common);
1073ff48bf5SDavid du Colombier gs_private_st_suffix_add9(st_image3x_enum, gx_image3x_enum_t,
1083ff48bf5SDavid du Colombier "gx_image3x_enum_t", image3x_enum_enum_ptrs, image3x_enum_reloc_ptrs,
1093ff48bf5SDavid du Colombier st_gx_image_enum_common, pcdev, mask[0].info, mask[0].mdev, mask[0].data,
1103ff48bf5SDavid du Colombier mask[1].info, mask[1].mdev, mask[1].data, pixel.info, pixel.data);
1113ff48bf5SDavid du Colombier
1123ff48bf5SDavid du Colombier /*
1133ff48bf5SDavid du Colombier * Begin a generic ImageType 3x image, with client handling the creation of
1143ff48bf5SDavid du Colombier * the mask image and mask clip devices.
1153ff48bf5SDavid du Colombier */
1163ff48bf5SDavid du Colombier typedef struct image3x_channel_values_s {
1173ff48bf5SDavid du Colombier gs_matrix matrix;
1183ff48bf5SDavid du Colombier gs_point corner;
1193ff48bf5SDavid du Colombier gs_int_rect rect;
1203ff48bf5SDavid du Colombier gs_image_t image;
1213ff48bf5SDavid du Colombier } image3x_channel_values_t;
122*593dc095SDavid du Colombier private int check_image3x_mask(const gs_image3x_t *pim,
1233ff48bf5SDavid du Colombier const gs_image3x_mask_t *pimm,
1243ff48bf5SDavid du Colombier const image3x_channel_values_t *ppcv,
1253ff48bf5SDavid du Colombier image3x_channel_values_t *pmcv,
1263ff48bf5SDavid du Colombier image3x_channel_state_t *pmcs,
127*593dc095SDavid du Colombier gs_memory_t *mem);
1283ff48bf5SDavid du Colombier int
gx_begin_image3x_generic(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,image3x_make_mid_proc_t make_mid,image3x_make_mcde_proc_t make_mcde,gx_image_enum_common_t ** pinfo)1293ff48bf5SDavid du Colombier gx_begin_image3x_generic(gx_device * dev,
1303ff48bf5SDavid du Colombier const gs_imager_state *pis, const gs_matrix *pmat,
1313ff48bf5SDavid du Colombier const gs_image_common_t *pic, const gs_int_rect *prect,
1323ff48bf5SDavid du Colombier const gx_drawing_color *pdcolor,
1333ff48bf5SDavid du Colombier const gx_clip_path *pcpath, gs_memory_t *mem,
1343ff48bf5SDavid du Colombier image3x_make_mid_proc_t make_mid,
1353ff48bf5SDavid du Colombier image3x_make_mcde_proc_t make_mcde,
1363ff48bf5SDavid du Colombier gx_image_enum_common_t **pinfo)
1373ff48bf5SDavid du Colombier {
1383ff48bf5SDavid du Colombier const gs_image3x_t *pim = (const gs_image3x_t *)pic;
1393ff48bf5SDavid du Colombier gx_image3x_enum_t *penum;
1403ff48bf5SDavid du Colombier gx_device *pcdev = 0;
1413ff48bf5SDavid du Colombier image3x_channel_values_t mask[2], pixel;
1423ff48bf5SDavid du Colombier gs_matrix mat;
1433ff48bf5SDavid du Colombier gx_device *midev[2];
1443ff48bf5SDavid du Colombier gx_image_enum_common_t *minfo[2];
1453ff48bf5SDavid du Colombier gs_int_point origin[2];
1463ff48bf5SDavid du Colombier int code;
1473ff48bf5SDavid du Colombier int i;
1483ff48bf5SDavid du Colombier
1493ff48bf5SDavid du Colombier /* Validate the parameters. */
1503ff48bf5SDavid du Colombier if (pim->Height <= 0)
1513ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
1523ff48bf5SDavid du Colombier penum = gs_alloc_struct(mem, gx_image3x_enum_t, &st_image3x_enum,
1533ff48bf5SDavid du Colombier "gx_begin_image3x");
1543ff48bf5SDavid du Colombier if (penum == 0)
1553ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
1563ff48bf5SDavid du Colombier /* Initialize pointers now in case we bail out. */
1573ff48bf5SDavid du Colombier penum->mask[0].info = 0, penum->mask[0].mdev = 0, penum->mask[0].data = 0;
1583ff48bf5SDavid du Colombier penum->mask[1].info = 0, penum->mask[1].mdev = 0, penum->mask[1].data = 0;
1593ff48bf5SDavid du Colombier penum->pixel.info = 0, penum->pixel.data = 0;
1603ff48bf5SDavid du Colombier if (prect)
1613ff48bf5SDavid du Colombier pixel.rect = *prect;
1623ff48bf5SDavid du Colombier else {
1633ff48bf5SDavid du Colombier pixel.rect.p.x = pixel.rect.p.y = 0;
1643ff48bf5SDavid du Colombier pixel.rect.q.x = pim->Width;
1653ff48bf5SDavid du Colombier pixel.rect.q.y = pim->Height;
1663ff48bf5SDavid du Colombier }
1673ff48bf5SDavid du Colombier if ((code = gs_matrix_invert(&pim->ImageMatrix, &pixel.matrix)) < 0 ||
1683ff48bf5SDavid du Colombier (code = gs_point_transform(pim->Width, pim->Height, &pixel.matrix,
1693ff48bf5SDavid du Colombier &pixel.corner)) < 0 ||
1703ff48bf5SDavid du Colombier (code = check_image3x_mask(pim, &pim->Opacity, &pixel, &mask[0],
1713ff48bf5SDavid du Colombier &penum->mask[0], mem)) < 0 ||
1723ff48bf5SDavid du Colombier (code = check_image3x_mask(pim, &pim->Shape, &pixel, &mask[1],
1733ff48bf5SDavid du Colombier &penum->mask[1], mem)) < 0
1743ff48bf5SDavid du Colombier ) {
1753ff48bf5SDavid du Colombier goto out0;
1763ff48bf5SDavid du Colombier }
1773ff48bf5SDavid du Colombier penum->num_components =
1783ff48bf5SDavid du Colombier gs_color_space_num_components(pim->ColorSpace);
1793ff48bf5SDavid du Colombier gx_image_enum_common_init((gx_image_enum_common_t *) penum,
1803ff48bf5SDavid du Colombier (const gs_data_image_t *)pim,
1813ff48bf5SDavid du Colombier &image3x_enum_procs, dev,
1823ff48bf5SDavid du Colombier 1 + penum->num_components,
1833ff48bf5SDavid du Colombier pim->format);
1843ff48bf5SDavid du Colombier penum->pixel.width = pixel.rect.q.x - pixel.rect.p.x;
1853ff48bf5SDavid du Colombier penum->pixel.height = pixel.rect.q.y - pixel.rect.p.y;
1863ff48bf5SDavid du Colombier penum->pixel.full_height = pim->Height;
1873ff48bf5SDavid du Colombier penum->pixel.y = 0;
1883ff48bf5SDavid du Colombier if (penum->mask[0].data || penum->mask[1].data) {
1893ff48bf5SDavid du Colombier /* Also allocate a row buffer for the pixel data. */
1903ff48bf5SDavid du Colombier penum->pixel.data =
1913ff48bf5SDavid du Colombier gs_alloc_bytes(mem,
1923ff48bf5SDavid du Colombier (penum->pixel.width * pim->BitsPerComponent *
1933ff48bf5SDavid du Colombier penum->num_components + 7) >> 3,
1943ff48bf5SDavid du Colombier "gx_begin_image3x(pixel.data)");
1953ff48bf5SDavid du Colombier if (penum->pixel.data == 0) {
1963ff48bf5SDavid du Colombier code = gs_note_error(gs_error_VMerror);
1973ff48bf5SDavid du Colombier goto out1;
1983ff48bf5SDavid du Colombier }
1993ff48bf5SDavid du Colombier }
2003ff48bf5SDavid du Colombier penum->bpc = pim->BitsPerComponent;
2013ff48bf5SDavid du Colombier penum->memory = mem;
2023ff48bf5SDavid du Colombier if (pmat == 0)
2033ff48bf5SDavid du Colombier pmat = &ctm_only(pis);
2043ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i) {
2053ff48bf5SDavid du Colombier gs_rect mrect;
2063ff48bf5SDavid du Colombier gx_device *mdev;
2073ff48bf5SDavid du Colombier /*
2083ff48bf5SDavid du Colombier * The mask data has to be defined in a DevicePixel color space
2093ff48bf5SDavid du Colombier * of the correct depth so that no color mapping will occur.
2103ff48bf5SDavid du Colombier */
2113ff48bf5SDavid du Colombier /****** FREE COLOR SPACE ON ERROR OR AT END ******/
2123ff48bf5SDavid du Colombier gs_color_space *pmcs;
2133ff48bf5SDavid du Colombier
2143ff48bf5SDavid du Colombier if (penum->mask[i].depth == 0) { /* mask not supplied */
215*593dc095SDavid du Colombier midev[i] = 0;
216*593dc095SDavid du Colombier minfo[i] = 0;
2173ff48bf5SDavid du Colombier continue;
2183ff48bf5SDavid du Colombier }
2193ff48bf5SDavid du Colombier pmcs = gs_alloc_struct(mem, gs_color_space, &st_color_space,
2203ff48bf5SDavid du Colombier "gx_begin_image3x_generic");
2213ff48bf5SDavid du Colombier if (pmcs == 0)
2223ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
223*593dc095SDavid du Colombier gs_cspace_init_DevicePixel(mem, pmcs, penum->mask[i].depth);
2243ff48bf5SDavid du Colombier mrect.p.x = mrect.p.y = 0;
2253ff48bf5SDavid du Colombier mrect.q.x = penum->mask[i].width;
2263ff48bf5SDavid du Colombier mrect.q.y = penum->mask[i].height;
2273ff48bf5SDavid du Colombier if ((code = gs_matrix_multiply(&mask[i].matrix, pmat, &mat)) < 0 ||
2283ff48bf5SDavid du Colombier (code = gs_bbox_transform(&mrect, &mat, &mrect)) < 0
2293ff48bf5SDavid du Colombier )
2303ff48bf5SDavid du Colombier return code;
231*593dc095SDavid du Colombier origin[i].x = (int)floor(mrect.p.x);
232*593dc095SDavid du Colombier origin[i].y = (int)floor(mrect.p.y);
2333ff48bf5SDavid du Colombier code = make_mid(&mdev, dev,
2343ff48bf5SDavid du Colombier (int)ceil(mrect.q.x) - origin[i].x,
2353ff48bf5SDavid du Colombier (int)ceil(mrect.q.y) - origin[i].y,
2363ff48bf5SDavid du Colombier penum->mask[i].depth, mem);
2373ff48bf5SDavid du Colombier if (code < 0)
2383ff48bf5SDavid du Colombier goto out1;
2393ff48bf5SDavid du Colombier penum->mask[i].mdev = mdev;
240*593dc095SDavid du Colombier gs_image_t_init(&mask[i].image, pmcs);
2413ff48bf5SDavid du Colombier mask[i].image.ColorSpace = pmcs;
2423ff48bf5SDavid du Colombier mask[i].image.adjust = false;
2433ff48bf5SDavid du Colombier {
2443ff48bf5SDavid du Colombier const gx_image_type_t *type1 = mask[i].image.type;
2453ff48bf5SDavid du Colombier const gs_image3x_mask_t *pixm =
2463ff48bf5SDavid du Colombier (i == 0 ? &pim->Opacity : &pim->Shape);
2473ff48bf5SDavid du Colombier
2483ff48bf5SDavid du Colombier *(gs_data_image_t *)&mask[i].image = pixm->MaskDict;
2493ff48bf5SDavid du Colombier mask[i].image.type = type1;
2503ff48bf5SDavid du Colombier mask[i].image.BitsPerComponent = pixm->MaskDict.BitsPerComponent;
2513ff48bf5SDavid du Colombier }
2523ff48bf5SDavid du Colombier {
2533ff48bf5SDavid du Colombier gs_matrix m_mat;
2543ff48bf5SDavid du Colombier
2553ff48bf5SDavid du Colombier /*
2563ff48bf5SDavid du Colombier * Adjust the translation for rendering the mask to include a
2573ff48bf5SDavid du Colombier * negative translation by origin.{x,y} in device space.
2583ff48bf5SDavid du Colombier */
2593ff48bf5SDavid du Colombier m_mat = *pmat;
2603ff48bf5SDavid du Colombier m_mat.tx -= origin[i].x;
2613ff48bf5SDavid du Colombier m_mat.ty -= origin[i].y;
2623ff48bf5SDavid du Colombier /*
2633ff48bf5SDavid du Colombier * Note that pis = NULL here, since we don't want to have to
2643ff48bf5SDavid du Colombier * create another imager state with default log_op, etc.
2653ff48bf5SDavid du Colombier * dcolor = NULL is OK because this is an opaque image with
2663ff48bf5SDavid du Colombier * CombineWithColor = false.
2673ff48bf5SDavid du Colombier */
2683ff48bf5SDavid du Colombier code = gx_device_begin_typed_image(mdev, NULL, &m_mat,
2693ff48bf5SDavid du Colombier (const gs_image_common_t *)&mask[i].image,
2703ff48bf5SDavid du Colombier &mask[i].rect, NULL, NULL,
2713ff48bf5SDavid du Colombier mem, &penum->mask[i].info);
2723ff48bf5SDavid du Colombier if (code < 0)
2733ff48bf5SDavid du Colombier goto out2;
2743ff48bf5SDavid du Colombier }
2753ff48bf5SDavid du Colombier midev[i] = mdev;
2763ff48bf5SDavid du Colombier minfo[i] = penum->mask[i].info;
2773ff48bf5SDavid du Colombier }
2783ff48bf5SDavid du Colombier gs_image_t_init(&pixel.image, pim->ColorSpace);
2793ff48bf5SDavid du Colombier {
2803ff48bf5SDavid du Colombier const gx_image_type_t *type1 = pixel.image.type;
2813ff48bf5SDavid du Colombier
2823ff48bf5SDavid du Colombier *(gs_pixel_image_t *)&pixel.image = *(const gs_pixel_image_t *)pim;
2833ff48bf5SDavid du Colombier pixel.image.type = type1;
2843ff48bf5SDavid du Colombier }
2853ff48bf5SDavid du Colombier code = make_mcde(dev, pis, pmat, (const gs_image_common_t *)&pixel.image,
2863ff48bf5SDavid du Colombier prect, pdcolor, pcpath, mem, &penum->pixel.info,
2873ff48bf5SDavid du Colombier &pcdev, midev, minfo, origin, pim);
2883ff48bf5SDavid du Colombier if (code < 0)
2893ff48bf5SDavid du Colombier goto out3;
2903ff48bf5SDavid du Colombier penum->pcdev = pcdev;
2913ff48bf5SDavid du Colombier /*
2923ff48bf5SDavid du Colombier * Set num_planes, plane_widths, and plane_depths from the values in the
2933ff48bf5SDavid du Colombier * enumerators for the mask(s) and the image data.
2943ff48bf5SDavid du Colombier */
2953ff48bf5SDavid du Colombier {
2963ff48bf5SDavid du Colombier int added_depth = 0;
2973ff48bf5SDavid du Colombier int pi = 0;
2983ff48bf5SDavid du Colombier
2993ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i) {
3003ff48bf5SDavid du Colombier if (penum->mask[i].depth == 0) /* no mask */
3013ff48bf5SDavid du Colombier continue;
3023ff48bf5SDavid du Colombier switch (penum->mask[i].InterleaveType) {
3033ff48bf5SDavid du Colombier case interleave_chunky:
3043ff48bf5SDavid du Colombier /* Add the mask data to the depth of the image data. */
3053ff48bf5SDavid du Colombier added_depth += pim->BitsPerComponent;
3063ff48bf5SDavid du Colombier break;
3073ff48bf5SDavid du Colombier case interleave_separate_source:
3083ff48bf5SDavid du Colombier /* Insert the mask as a separate plane. */
3093ff48bf5SDavid du Colombier penum->plane_widths[pi] = penum->mask[i].width;
3103ff48bf5SDavid du Colombier penum->plane_depths[pi] = penum->mask[i].depth;
3113ff48bf5SDavid du Colombier ++pi;
3123ff48bf5SDavid du Colombier break;
3133ff48bf5SDavid du Colombier default: /* can't happen */
3143ff48bf5SDavid du Colombier code = gs_note_error(gs_error_Fatal);
3153ff48bf5SDavid du Colombier goto out3;
3163ff48bf5SDavid du Colombier }
3173ff48bf5SDavid du Colombier }
3183ff48bf5SDavid du Colombier memcpy(&penum->plane_widths[pi], &penum->pixel.info->plane_widths[0],
3193ff48bf5SDavid du Colombier penum->pixel.info->num_planes * sizeof(penum->plane_widths[0]));
3203ff48bf5SDavid du Colombier memcpy(&penum->plane_depths[pi], &penum->pixel.info->plane_depths[0],
3213ff48bf5SDavid du Colombier penum->pixel.info->num_planes * sizeof(penum->plane_depths[0]));
3223ff48bf5SDavid du Colombier penum->plane_depths[pi] += added_depth;
3233ff48bf5SDavid du Colombier penum->num_planes = pi + penum->pixel.info->num_planes;
3243ff48bf5SDavid du Colombier }
3253ff48bf5SDavid du Colombier if (midev[0])
3263ff48bf5SDavid du Colombier gx_device_retain(midev[0], true); /* will free explicitly */
3273ff48bf5SDavid du Colombier if (midev[1])
3283ff48bf5SDavid du Colombier gx_device_retain(midev[1], true); /* ditto */
3293ff48bf5SDavid du Colombier gx_device_retain(pcdev, true); /* ditto */
3303ff48bf5SDavid du Colombier *pinfo = (gx_image_enum_common_t *) penum;
3313ff48bf5SDavid du Colombier return 0;
3323ff48bf5SDavid du Colombier out3:
3333ff48bf5SDavid du Colombier if (penum->mask[1].info)
3343ff48bf5SDavid du Colombier gx_image_end(penum->mask[1].info, false);
3353ff48bf5SDavid du Colombier if (penum->mask[0].info)
3363ff48bf5SDavid du Colombier gx_image_end(penum->mask[0].info, false);
3373ff48bf5SDavid du Colombier out2:
3383ff48bf5SDavid du Colombier if (penum->mask[1].mdev) {
3393ff48bf5SDavid du Colombier gs_closedevice(penum->mask[1].mdev);
3403ff48bf5SDavid du Colombier gs_free_object(mem, penum->mask[1].mdev,
3413ff48bf5SDavid du Colombier "gx_begin_image3x(mask[1].mdev)");
3423ff48bf5SDavid du Colombier }
3433ff48bf5SDavid du Colombier if (penum->mask[0].mdev) {
3443ff48bf5SDavid du Colombier gs_closedevice(penum->mask[0].mdev);
3453ff48bf5SDavid du Colombier gs_free_object(mem, penum->mask[0].mdev,
3463ff48bf5SDavid du Colombier "gx_begin_image3x(mask[0].mdev)");
3473ff48bf5SDavid du Colombier }
3483ff48bf5SDavid du Colombier out1:
3493ff48bf5SDavid du Colombier gs_free_object(mem, penum->mask[0].data, "gx_begin_image3x(mask[0].data)");
3503ff48bf5SDavid du Colombier gs_free_object(mem, penum->mask[1].data, "gx_begin_image3x(mask[1].data)");
3513ff48bf5SDavid du Colombier gs_free_object(mem, penum->pixel.data, "gx_begin_image3x(pixel.data)");
3523ff48bf5SDavid du Colombier out0:
3533ff48bf5SDavid du Colombier gs_free_object(mem, penum, "gx_begin_image3x");
3543ff48bf5SDavid du Colombier return code;
3553ff48bf5SDavid du Colombier }
3563ff48bf5SDavid du Colombier private bool
check_image3x_extent(floatp mask_coeff,floatp data_coeff)3573ff48bf5SDavid du Colombier check_image3x_extent(floatp mask_coeff, floatp data_coeff)
3583ff48bf5SDavid du Colombier {
3593ff48bf5SDavid du Colombier if (mask_coeff == 0)
3603ff48bf5SDavid du Colombier return data_coeff == 0;
3613ff48bf5SDavid du Colombier if (data_coeff == 0 || (mask_coeff > 0) != (data_coeff > 0))
3623ff48bf5SDavid du Colombier return false;
3633ff48bf5SDavid du Colombier return true;
3643ff48bf5SDavid du Colombier }
365*593dc095SDavid du Colombier /*
366*593dc095SDavid du Colombier * Check mask parameters.
367*593dc095SDavid du Colombier * Reads ppcv->{matrix,corner,rect}, sets pmcv->{matrix,corner,rect} and
368*593dc095SDavid du Colombier * pmcs->{InterleaveType,width,height,full_height,depth,data,y,skip}.
369*593dc095SDavid du Colombier * If the mask is omitted, sets pmcs->depth = 0 and returns normally.
370*593dc095SDavid du Colombier */
3713ff48bf5SDavid du Colombier private bool
check_image3x_mask(const gs_image3x_t * pim,const gs_image3x_mask_t * pimm,const image3x_channel_values_t * ppcv,image3x_channel_values_t * pmcv,image3x_channel_state_t * pmcs,gs_memory_t * mem)3723ff48bf5SDavid du Colombier check_image3x_mask(const gs_image3x_t *pim, const gs_image3x_mask_t *pimm,
3733ff48bf5SDavid du Colombier const image3x_channel_values_t *ppcv,
3743ff48bf5SDavid du Colombier image3x_channel_values_t *pmcv,
3753ff48bf5SDavid du Colombier image3x_channel_state_t *pmcs, gs_memory_t *mem)
3763ff48bf5SDavid du Colombier {
3773ff48bf5SDavid du Colombier int mask_width = pimm->MaskDict.Width, mask_height = pimm->MaskDict.Height;
3783ff48bf5SDavid du Colombier int code;
3793ff48bf5SDavid du Colombier
380*593dc095SDavid du Colombier if (pimm->MaskDict.BitsPerComponent == 0) { /* mask missing */
381*593dc095SDavid du Colombier pmcs->depth = 0;
382*593dc095SDavid du Colombier pmcs->InterleaveType = 0; /* not a valid type */
3833ff48bf5SDavid du Colombier return 0;
384*593dc095SDavid du Colombier }
3853ff48bf5SDavid du Colombier if (mask_height <= 0)
3863ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
3873ff48bf5SDavid du Colombier switch (pimm->InterleaveType) {
3883ff48bf5SDavid du Colombier /*case interleave_scan_lines:*/ /* not supported */
3893ff48bf5SDavid du Colombier default:
3903ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
3913ff48bf5SDavid du Colombier case interleave_chunky:
3923ff48bf5SDavid du Colombier if (mask_width != pim->Width ||
3933ff48bf5SDavid du Colombier mask_height != pim->Height ||
3943ff48bf5SDavid du Colombier pimm->MaskDict.BitsPerComponent != pim->BitsPerComponent ||
3953ff48bf5SDavid du Colombier pim->format != gs_image_format_chunky
3963ff48bf5SDavid du Colombier )
3973ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
3983ff48bf5SDavid du Colombier break;
3993ff48bf5SDavid du Colombier case interleave_separate_source:
4003ff48bf5SDavid du Colombier switch (pimm->MaskDict.BitsPerComponent) {
4013ff48bf5SDavid du Colombier case 1: case 2: case 4: case 8:
4023ff48bf5SDavid du Colombier break;
4033ff48bf5SDavid du Colombier default:
4043ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
4053ff48bf5SDavid du Colombier }
4063ff48bf5SDavid du Colombier }
4073ff48bf5SDavid du Colombier if (!check_image3x_extent(pim->ImageMatrix.xx,
4083ff48bf5SDavid du Colombier pimm->MaskDict.ImageMatrix.xx) ||
4093ff48bf5SDavid du Colombier !check_image3x_extent(pim->ImageMatrix.xy,
4103ff48bf5SDavid du Colombier pimm->MaskDict.ImageMatrix.xy) ||
4113ff48bf5SDavid du Colombier !check_image3x_extent(pim->ImageMatrix.yx,
4123ff48bf5SDavid du Colombier pimm->MaskDict.ImageMatrix.yx) ||
4133ff48bf5SDavid du Colombier !check_image3x_extent(pim->ImageMatrix.yy,
4143ff48bf5SDavid du Colombier pimm->MaskDict.ImageMatrix.yy)
4153ff48bf5SDavid du Colombier )
4163ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
4173ff48bf5SDavid du Colombier if ((code = gs_matrix_invert(&pimm->MaskDict.ImageMatrix, &pmcv->matrix)) < 0 ||
4183ff48bf5SDavid du Colombier (code = gs_point_transform(mask_width, mask_height,
4193ff48bf5SDavid du Colombier &pmcv->matrix, &pmcv->corner)) < 0
4203ff48bf5SDavid du Colombier )
4213ff48bf5SDavid du Colombier return code;
4223ff48bf5SDavid du Colombier if (fabs(ppcv->matrix.tx - pmcv->matrix.tx) >= 0.5 ||
4233ff48bf5SDavid du Colombier fabs(ppcv->matrix.ty - pmcv->matrix.ty) >= 0.5 ||
4243ff48bf5SDavid du Colombier fabs(ppcv->corner.x - pmcv->corner.x) >= 0.5 ||
4253ff48bf5SDavid du Colombier fabs(ppcv->corner.y - pmcv->corner.y) >= 0.5
4263ff48bf5SDavid du Colombier )
4273ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
4283ff48bf5SDavid du Colombier pmcv->rect.p.x = ppcv->rect.p.x * mask_width / pim->Width;
4293ff48bf5SDavid du Colombier pmcv->rect.p.y = ppcv->rect.p.y * mask_height / pim->Height;
4303ff48bf5SDavid du Colombier pmcv->rect.q.x = (ppcv->rect.q.x * mask_width + pim->Width - 1) /
4313ff48bf5SDavid du Colombier pim->Width;
4323ff48bf5SDavid du Colombier pmcv->rect.q.y = (ppcv->rect.q.y * mask_height + pim->Height - 1) /
4333ff48bf5SDavid du Colombier pim->Height;
4343ff48bf5SDavid du Colombier /* Initialize the channel state in the enumerator. */
4353ff48bf5SDavid du Colombier pmcs->InterleaveType = pimm->InterleaveType;
4363ff48bf5SDavid du Colombier pmcs->width = pmcv->rect.q.x - pmcv->rect.p.x;
4373ff48bf5SDavid du Colombier pmcs->height = pmcv->rect.q.y - pmcv->rect.p.y;
4383ff48bf5SDavid du Colombier pmcs->full_height = pimm->MaskDict.Height;
4393ff48bf5SDavid du Colombier pmcs->depth = pimm->MaskDict.BitsPerComponent;
4403ff48bf5SDavid du Colombier if (pmcs->InterleaveType == interleave_chunky) {
4413ff48bf5SDavid du Colombier /* Allocate a buffer for the data. */
4423ff48bf5SDavid du Colombier pmcs->data =
4433ff48bf5SDavid du Colombier gs_alloc_bytes(mem,
4443ff48bf5SDavid du Colombier (pmcs->width * pimm->MaskDict.BitsPerComponent + 7) >> 3,
4453ff48bf5SDavid du Colombier "gx_begin_image3x(mask data)");
4463ff48bf5SDavid du Colombier if (pmcs->data == 0)
4473ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
4483ff48bf5SDavid du Colombier }
4493ff48bf5SDavid du Colombier pmcs->y = pmcs->skip = 0;
4503ff48bf5SDavid du Colombier return 0;
4513ff48bf5SDavid du Colombier }
4523ff48bf5SDavid du Colombier
4533ff48bf5SDavid du Colombier /*
4543ff48bf5SDavid du Colombier * Return > 0 if we want more data from channel 1 now, < 0 if we want more
4553ff48bf5SDavid du Colombier * from channel 2 now, 0 if we want both.
4563ff48bf5SDavid du Colombier */
4573ff48bf5SDavid du Colombier private int
channel_next(const image3x_channel_state_t * pics1,const image3x_channel_state_t * pics2)4583ff48bf5SDavid du Colombier channel_next(const image3x_channel_state_t *pics1,
4593ff48bf5SDavid du Colombier const image3x_channel_state_t *pics2)
4603ff48bf5SDavid du Colombier {
4613ff48bf5SDavid du Colombier /*
4623ff48bf5SDavid du Colombier * The invariant we need to maintain is that we always have at least as
4633ff48bf5SDavid du Colombier * much channel N as channel N+1 data, where N = 0 = opacity, 1 = shape,
4643ff48bf5SDavid du Colombier * and 2 = pixel. I.e., for any two consecutive channels c1 and c2, we
4653ff48bf5SDavid du Colombier * require c1.y / c1.full_height >= c2.y / c2.full_height, or, to avoid
4663ff48bf5SDavid du Colombier * floating point, c1.y * c2.full_height >= c2.y * c1.full_height. We
4673ff48bf5SDavid du Colombier * know this condition is true now; return a value that indicates how to
4683ff48bf5SDavid du Colombier * maintain it.
4693ff48bf5SDavid du Colombier */
4703ff48bf5SDavid du Colombier int h1 = pics1->full_height;
4713ff48bf5SDavid du Colombier int h2 = pics2->full_height;
4723ff48bf5SDavid du Colombier long current = pics1->y * (long)h2 - pics2->y * (long)h1;
4733ff48bf5SDavid du Colombier
4743ff48bf5SDavid du Colombier #ifdef DEBUG
4753ff48bf5SDavid du Colombier if (current < 0)
4763ff48bf5SDavid du Colombier lprintf4("channel_next invariant fails: %d/%d < %d/%d\n",
4773ff48bf5SDavid du Colombier pics1->y, pics1->full_height,
4783ff48bf5SDavid du Colombier pics2->y, pics2->full_height);
4793ff48bf5SDavid du Colombier #endif
4803ff48bf5SDavid du Colombier return ((current -= h1) >= 0 ? -1 :
4813ff48bf5SDavid du Colombier current + h2 >= 0 ? 0 : 1);
4823ff48bf5SDavid du Colombier }
4833ff48bf5SDavid du Colombier
4843ff48bf5SDavid du Colombier /* Define the default implementation of ImageType 3 processing. */
4853ff48bf5SDavid du Colombier private IMAGE3X_MAKE_MID_PROC(make_midx_default); /* check prototype */
4863ff48bf5SDavid du Colombier private int
make_midx_default(gx_device ** pmidev,gx_device * dev,int width,int height,int depth,gs_memory_t * mem)4873ff48bf5SDavid du Colombier make_midx_default(gx_device **pmidev, gx_device *dev, int width, int height,
4883ff48bf5SDavid du Colombier int depth, gs_memory_t *mem)
4893ff48bf5SDavid du Colombier {
4903ff48bf5SDavid du Colombier const gx_device_memory *mdproto = gdev_mem_device_for_bits(depth);
4913ff48bf5SDavid du Colombier gx_device_memory *midev;
4923ff48bf5SDavid du Colombier int code;
4933ff48bf5SDavid du Colombier
4943ff48bf5SDavid du Colombier if (mdproto == 0)
4953ff48bf5SDavid du Colombier return_error(gs_error_rangecheck);
4963ff48bf5SDavid du Colombier midev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
4973ff48bf5SDavid du Colombier "make_mid_default");
4983ff48bf5SDavid du Colombier if (midev == 0)
4993ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
5003ff48bf5SDavid du Colombier gs_make_mem_device(midev, mdproto, mem, 0, NULL);
5013ff48bf5SDavid du Colombier midev->bitmap_memory = mem;
5023ff48bf5SDavid du Colombier midev->width = width;
5033ff48bf5SDavid du Colombier midev->height = height;
504*593dc095SDavid du Colombier check_device_separable((gx_device *)midev);
5053ff48bf5SDavid du Colombier gx_device_fill_in_procs((gx_device *)midev);
5063ff48bf5SDavid du Colombier code = dev_proc(midev, open_device)((gx_device *)midev);
5073ff48bf5SDavid du Colombier if (code < 0) {
5083ff48bf5SDavid du Colombier gs_free_object(mem, midev, "make_midx_default");
5093ff48bf5SDavid du Colombier return code;
5103ff48bf5SDavid du Colombier }
5113ff48bf5SDavid du Colombier midev->is_open = true;
5123ff48bf5SDavid du Colombier dev_proc(midev, fill_rectangle)
5133ff48bf5SDavid du Colombier ((gx_device *)midev, 0, 0, width, height, (gx_color_index)0);
5143ff48bf5SDavid du Colombier *pmidev = (gx_device *)midev;
5153ff48bf5SDavid du Colombier return 0;
5163ff48bf5SDavid du Colombier }
5173ff48bf5SDavid du Colombier private IMAGE3X_MAKE_MCDE_PROC(make_mcdex_default); /* check prototype */
5183ff48bf5SDavid du Colombier private int
make_mcdex_default(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo,gx_device ** pmcdev,gx_device * midev[2],gx_image_enum_common_t * pminfo[2],const gs_int_point origin[2],const gs_image3x_t * pim)5193ff48bf5SDavid du Colombier make_mcdex_default(gx_device *dev, const gs_imager_state *pis,
5203ff48bf5SDavid du Colombier const gs_matrix *pmat, const gs_image_common_t *pic,
5213ff48bf5SDavid du Colombier const gs_int_rect *prect, const gx_drawing_color *pdcolor,
5223ff48bf5SDavid du Colombier const gx_clip_path *pcpath, gs_memory_t *mem,
5233ff48bf5SDavid du Colombier gx_image_enum_common_t **pinfo,
5243ff48bf5SDavid du Colombier gx_device **pmcdev, gx_device *midev[2],
5253ff48bf5SDavid du Colombier gx_image_enum_common_t *pminfo[2],
5263ff48bf5SDavid du Colombier const gs_int_point origin[2],
5273ff48bf5SDavid du Colombier const gs_image3x_t *pim)
5283ff48bf5SDavid du Colombier {
5293ff48bf5SDavid du Colombier /**************** NYI ****************/
5303ff48bf5SDavid du Colombier /*
5313ff48bf5SDavid du Colombier * There is no soft-mask analogue of make_mcde_default, because
5323ff48bf5SDavid du Colombier * soft-mask clipping is a more complicated operation, implemented
5333ff48bf5SDavid du Colombier * by the general transparency code. As a default, we simply ignore
5343ff48bf5SDavid du Colombier * the soft mask. However, we have to create an intermediate device
5353ff48bf5SDavid du Colombier * that can be freed at the end and that simply forwards all calls.
5363ff48bf5SDavid du Colombier * The most convenient device for this purpose is the bbox device.
5373ff48bf5SDavid du Colombier */
5383ff48bf5SDavid du Colombier gx_device_bbox *bbdev =
5393ff48bf5SDavid du Colombier gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox,
5403ff48bf5SDavid du Colombier "make_mcdex_default");
5413ff48bf5SDavid du Colombier int code;
5423ff48bf5SDavid du Colombier
5433ff48bf5SDavid du Colombier if (bbdev == 0)
5443ff48bf5SDavid du Colombier return_error(gs_error_VMerror);
545*593dc095SDavid du Colombier gx_device_bbox_init(bbdev, dev, mem);
5463ff48bf5SDavid du Colombier gx_device_bbox_fwd_open_close(bbdev, false);
5473ff48bf5SDavid du Colombier code = dev_proc(bbdev, begin_typed_image)
5483ff48bf5SDavid du Colombier ((gx_device *)bbdev, pis, pmat, pic, prect, pdcolor, pcpath, mem,
5493ff48bf5SDavid du Colombier pinfo);
5503ff48bf5SDavid du Colombier if (code < 0) {
5513ff48bf5SDavid du Colombier gs_free_object(mem, bbdev, "make_mcdex_default");
5523ff48bf5SDavid du Colombier return code;
5533ff48bf5SDavid du Colombier }
5543ff48bf5SDavid du Colombier *pmcdev = (gx_device *)bbdev;
5553ff48bf5SDavid du Colombier return 0;
5563ff48bf5SDavid du Colombier }
5573ff48bf5SDavid du Colombier private int
gx_begin_image3x(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo)5583ff48bf5SDavid du Colombier gx_begin_image3x(gx_device * dev,
5593ff48bf5SDavid du Colombier const gs_imager_state * pis, const gs_matrix * pmat,
5603ff48bf5SDavid du Colombier const gs_image_common_t * pic, const gs_int_rect * prect,
5613ff48bf5SDavid du Colombier const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
5623ff48bf5SDavid du Colombier gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
5633ff48bf5SDavid du Colombier {
5643ff48bf5SDavid du Colombier return gx_begin_image3x_generic(dev, pis, pmat, pic, prect, pdcolor,
5653ff48bf5SDavid du Colombier pcpath, mem, make_midx_default,
5663ff48bf5SDavid du Colombier make_mcdex_default, pinfo);
5673ff48bf5SDavid du Colombier }
5683ff48bf5SDavid du Colombier
5693ff48bf5SDavid du Colombier /* Process the next piece of an ImageType 3 image. */
5703ff48bf5SDavid du Colombier private int
gx_image3x_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)5713ff48bf5SDavid du Colombier gx_image3x_plane_data(gx_image_enum_common_t * info,
5723ff48bf5SDavid du Colombier const gx_image_plane_t * planes, int height,
5733ff48bf5SDavid du Colombier int *rows_used)
5743ff48bf5SDavid du Colombier {
5753ff48bf5SDavid du Colombier gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
5763ff48bf5SDavid du Colombier int pixel_height = penum->pixel.height;
5773ff48bf5SDavid du Colombier int pixel_used = 0;
5783ff48bf5SDavid du Colombier int mask_height[2];
5793ff48bf5SDavid du Colombier int mask_used[2];
5803ff48bf5SDavid du Colombier int h1 = pixel_height - penum->pixel.y;
5813ff48bf5SDavid du Colombier int h;
5823ff48bf5SDavid du Colombier const gx_image_plane_t *pixel_planes;
5833ff48bf5SDavid du Colombier gx_image_plane_t pixel_plane, mask_plane[2];
5843ff48bf5SDavid du Colombier int code = 0;
5853ff48bf5SDavid du Colombier int i, pi = 0;
5863ff48bf5SDavid du Colombier int num_chunky = 0;
5873ff48bf5SDavid du Colombier
5883ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i) {
5893ff48bf5SDavid du Colombier int mh = mask_height[i] = penum->mask[i].height;
5903ff48bf5SDavid du Colombier
5913ff48bf5SDavid du Colombier mask_plane[i].data = 0;
5923ff48bf5SDavid du Colombier mask_used[i] = 0;
5933ff48bf5SDavid du Colombier if (!penum->mask[i].depth)
5943ff48bf5SDavid du Colombier continue;
5953ff48bf5SDavid du Colombier h1 = min(h1, mh - penum->mask[i].y);
5963ff48bf5SDavid du Colombier if (penum->mask[i].InterleaveType == interleave_chunky)
5973ff48bf5SDavid du Colombier ++num_chunky;
5983ff48bf5SDavid du Colombier }
5993ff48bf5SDavid du Colombier h = min(height, h1);
6003ff48bf5SDavid du Colombier /* Initialized rows_used in case we get an error. */
6013ff48bf5SDavid du Colombier *rows_used = 0;
6023ff48bf5SDavid du Colombier if (h <= 0)
6033ff48bf5SDavid du Colombier return 0;
6043ff48bf5SDavid du Colombier
6053ff48bf5SDavid du Colombier /* Handle masks from separate sources. */
6063ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i)
6073ff48bf5SDavid du Colombier if (penum->mask[i].InterleaveType == interleave_separate_source) {
6083ff48bf5SDavid du Colombier /*
6093ff48bf5SDavid du Colombier * In order to be able to recover from interruptions, we must
6103ff48bf5SDavid du Colombier * limit separate-source processing to 1 scan line at a time.
6113ff48bf5SDavid du Colombier */
6123ff48bf5SDavid du Colombier if (h > 1)
6133ff48bf5SDavid du Colombier h = 1;
6143ff48bf5SDavid du Colombier mask_plane[i] = planes[pi++];
6153ff48bf5SDavid du Colombier }
6163ff48bf5SDavid du Colombier pixel_planes = &planes[pi];
6173ff48bf5SDavid du Colombier
6183ff48bf5SDavid du Colombier /* Handle chunky masks. */
6193ff48bf5SDavid du Colombier if (num_chunky) {
6203ff48bf5SDavid du Colombier int bpc = penum->bpc;
6213ff48bf5SDavid du Colombier int num_components = penum->num_components;
6223ff48bf5SDavid du Colombier int width = penum->pixel.width;
6233ff48bf5SDavid du Colombier /* Pull apart the source data and the mask data. */
6243ff48bf5SDavid du Colombier /* We do this in the simplest (not fastest) way for now. */
6253ff48bf5SDavid du Colombier uint bit_x = bpc * (num_components + num_chunky) * planes[pi].data_x;
6263ff48bf5SDavid du Colombier sample_load_declare_setup(sptr, sbit, planes[0].data + (bit_x >> 3),
6273ff48bf5SDavid du Colombier bit_x & 7, bpc);
6283ff48bf5SDavid du Colombier sample_store_declare_setup(pptr, pbit, pbbyte,
6293ff48bf5SDavid du Colombier penum->pixel.data, 0, bpc);
6303ff48bf5SDavid du Colombier sample_store_declare(dptr[NUM_MASKS], dbit[NUM_MASKS],
6313ff48bf5SDavid du Colombier dbbyte[NUM_MASKS]);
6323ff48bf5SDavid du Colombier int depth[NUM_MASKS];
6333ff48bf5SDavid du Colombier int x;
6343ff48bf5SDavid du Colombier
6353ff48bf5SDavid du Colombier if (h > 1) {
6363ff48bf5SDavid du Colombier /* Do the operation one row at a time. */
6373ff48bf5SDavid du Colombier h = 1;
6383ff48bf5SDavid du Colombier }
6393ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i)
6403ff48bf5SDavid du Colombier if (penum->mask[i].data) {
6413ff48bf5SDavid du Colombier depth[i] = penum->mask[i].depth;
6423ff48bf5SDavid du Colombier mask_plane[i].data = dptr[i] = penum->mask[i].data;
6433ff48bf5SDavid du Colombier mask_plane[i].data_x = 0;
6443ff48bf5SDavid du Colombier /* raster doesn't matter */
6453ff48bf5SDavid du Colombier sample_store_setup(dbit[i], 0, depth[i]);
6463ff48bf5SDavid du Colombier sample_store_preload(dbbyte[i], dptr[i], 0, depth[i]);
6473ff48bf5SDavid du Colombier } else
6483ff48bf5SDavid du Colombier depth[i] = 0;
6493ff48bf5SDavid du Colombier pixel_plane.data = pptr;
6503ff48bf5SDavid du Colombier pixel_plane.data_x = 0;
6513ff48bf5SDavid du Colombier /* raster doesn't matter */
6523ff48bf5SDavid du Colombier pixel_planes = &pixel_plane;
6533ff48bf5SDavid du Colombier for (x = 0; x < width; ++x) {
6543ff48bf5SDavid du Colombier uint value;
6553ff48bf5SDavid du Colombier
6563ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i)
6573ff48bf5SDavid du Colombier if (depth[i]) {
6583ff48bf5SDavid du Colombier sample_load_next12(value, sptr, sbit, bpc);
6593ff48bf5SDavid du Colombier sample_store_next12(value, dptr[i], dbit[i], depth[i],
6603ff48bf5SDavid du Colombier dbbyte[i]);
6613ff48bf5SDavid du Colombier }
6623ff48bf5SDavid du Colombier for (i = 0; i < num_components; ++i) {
6633ff48bf5SDavid du Colombier sample_load_next12(value, sptr, sbit, bpc);
6643ff48bf5SDavid du Colombier sample_store_next12(value, pptr, pbit, bpc, pbbyte);
6653ff48bf5SDavid du Colombier }
6663ff48bf5SDavid du Colombier }
6673ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i)
6683ff48bf5SDavid du Colombier if (penum->mask[i].data)
6693ff48bf5SDavid du Colombier sample_store_flush(dptr[i], dbit[i], depth[i], dbbyte[i]);
6703ff48bf5SDavid du Colombier sample_store_flush(pptr, pbit, bpc, pbbyte);
6713ff48bf5SDavid du Colombier }
6723ff48bf5SDavid du Colombier /*
6733ff48bf5SDavid du Colombier * Process the mask data first, so it will set up the mask
6743ff48bf5SDavid du Colombier * device for clipping the pixel data.
6753ff48bf5SDavid du Colombier */
6763ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i)
6773ff48bf5SDavid du Colombier if (mask_plane[i].data) {
6783ff48bf5SDavid du Colombier /*
6793ff48bf5SDavid du Colombier * If, on the last call, we processed some mask rows
6803ff48bf5SDavid du Colombier * successfully but processing the pixel rows was interrupted,
6813ff48bf5SDavid du Colombier * we set rows_used to indicate the number of pixel rows
6823ff48bf5SDavid du Colombier * processed (since there is no way to return two rows_used
6833ff48bf5SDavid du Colombier * values). If this happened, some mask rows may get presented
6843ff48bf5SDavid du Colombier * again. We must skip over them rather than processing them
6853ff48bf5SDavid du Colombier * again.
6863ff48bf5SDavid du Colombier */
6873ff48bf5SDavid du Colombier int skip = penum->mask[i].skip;
6883ff48bf5SDavid du Colombier
6893ff48bf5SDavid du Colombier if (skip >= h) {
6903ff48bf5SDavid du Colombier penum->mask[i].skip = skip - (mask_used[i] = h);
6913ff48bf5SDavid du Colombier } else {
6923ff48bf5SDavid du Colombier int mask_h = h - skip;
6933ff48bf5SDavid du Colombier
6943ff48bf5SDavid du Colombier mask_plane[i].data += skip * mask_plane[i].raster;
6953ff48bf5SDavid du Colombier penum->mask[i].skip = 0;
6963ff48bf5SDavid du Colombier code = gx_image_plane_data_rows(penum->mask[i].info,
6973ff48bf5SDavid du Colombier &mask_plane[i],
6983ff48bf5SDavid du Colombier mask_h, &mask_used[i]);
6993ff48bf5SDavid du Colombier mask_used[i] += skip;
7003ff48bf5SDavid du Colombier }
7013ff48bf5SDavid du Colombier *rows_used = mask_used[i];
7023ff48bf5SDavid du Colombier penum->mask[i].y += mask_used[i];
7033ff48bf5SDavid du Colombier if (code < 0)
7043ff48bf5SDavid du Colombier return code;
7053ff48bf5SDavid du Colombier }
7063ff48bf5SDavid du Colombier if (pixel_planes[0].data) {
7073ff48bf5SDavid du Colombier /*
7083ff48bf5SDavid du Colombier * If necessary, flush any buffered mask data to the mask clipping
7093ff48bf5SDavid du Colombier * device.
7103ff48bf5SDavid du Colombier */
7113ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i)
7123ff48bf5SDavid du Colombier if (penum->mask[i].info)
7133ff48bf5SDavid du Colombier gx_image_flush(penum->mask[i].info);
7143ff48bf5SDavid du Colombier code = gx_image_plane_data_rows(penum->pixel.info, pixel_planes, h,
7153ff48bf5SDavid du Colombier &pixel_used);
7163ff48bf5SDavid du Colombier /*
7173ff48bf5SDavid du Colombier * There isn't any way to set rows_used if different amounts of
7183ff48bf5SDavid du Colombier * the mask and pixel data were used. Fake it.
7193ff48bf5SDavid du Colombier */
7203ff48bf5SDavid du Colombier *rows_used = pixel_used;
7213ff48bf5SDavid du Colombier /*
7223ff48bf5SDavid du Colombier * Don't return code yet: we must account for the fact that
7233ff48bf5SDavid du Colombier * some mask data may have been processed.
7243ff48bf5SDavid du Colombier */
7253ff48bf5SDavid du Colombier penum->pixel.y += pixel_used;
7263ff48bf5SDavid du Colombier if (code < 0) {
7273ff48bf5SDavid du Colombier /*
7283ff48bf5SDavid du Colombier * We must prevent the mask data from being processed again.
7293ff48bf5SDavid du Colombier * We rely on the fact that h > 1 is only possible if the
7303ff48bf5SDavid du Colombier * mask and pixel data have the same Y scaling.
7313ff48bf5SDavid du Colombier */
7323ff48bf5SDavid du Colombier for (i = 0; i < NUM_MASKS; ++i)
7333ff48bf5SDavid du Colombier if (mask_used[i] > pixel_used) {
7343ff48bf5SDavid du Colombier int skip = mask_used[i] - pixel_used;
7353ff48bf5SDavid du Colombier
7363ff48bf5SDavid du Colombier penum->mask[i].skip = skip;
7373ff48bf5SDavid du Colombier penum->mask[i].y -= skip;
7383ff48bf5SDavid du Colombier mask_used[i] = pixel_used;
7393ff48bf5SDavid du Colombier }
7403ff48bf5SDavid du Colombier }
7413ff48bf5SDavid du Colombier }
7423ff48bf5SDavid du Colombier if_debug7('b', "[b]image3x h=%d %sopacity.y=%d %sopacity.y=%d %spixel.y=%d\n",
7433ff48bf5SDavid du Colombier h, (mask_plane[0].data ? "+" : ""), penum->mask[0].y,
7443ff48bf5SDavid du Colombier (mask_plane[1].data ? "+" : ""), penum->mask[1].y,
7453ff48bf5SDavid du Colombier (pixel_planes[0].data ? "+" : ""), penum->pixel.y);
7463ff48bf5SDavid du Colombier if (penum->mask[0].y >= penum->mask[0].height &&
7473ff48bf5SDavid du Colombier penum->mask[1].y >= penum->mask[1].height &&
7483ff48bf5SDavid du Colombier penum->pixel.y >= penum->pixel.height)
7493ff48bf5SDavid du Colombier return 1;
7503ff48bf5SDavid du Colombier /*
7513ff48bf5SDavid du Colombier * The mask may be complete (gx_image_plane_data_rows returned 1),
7523ff48bf5SDavid du Colombier * but there may still be pixel rows to go, so don't return 1 here.
7533ff48bf5SDavid du Colombier */
7543ff48bf5SDavid du Colombier return (code < 0 ? code : 0);
7553ff48bf5SDavid du Colombier }
7563ff48bf5SDavid du Colombier
7573ff48bf5SDavid du Colombier /* Flush buffered data. */
7583ff48bf5SDavid du Colombier private int
gx_image3x_flush(gx_image_enum_common_t * info)7593ff48bf5SDavid du Colombier gx_image3x_flush(gx_image_enum_common_t * info)
7603ff48bf5SDavid du Colombier {
7613ff48bf5SDavid du Colombier gx_image3x_enum_t * const penum = (gx_image3x_enum_t *) info;
7623ff48bf5SDavid du Colombier int code = gx_image_flush(penum->mask[0].info);
7633ff48bf5SDavid du Colombier
7643ff48bf5SDavid du Colombier if (code >= 0)
7653ff48bf5SDavid du Colombier code = gx_image_flush(penum->mask[1].info);
7663ff48bf5SDavid du Colombier if (code >= 0)
7673ff48bf5SDavid du Colombier code = gx_image_flush(penum->pixel.info);
7683ff48bf5SDavid du Colombier return code;
7693ff48bf5SDavid du Colombier }
7703ff48bf5SDavid du Colombier
7713ff48bf5SDavid du Colombier /* Determine which data planes are wanted. */
7723ff48bf5SDavid du Colombier private bool
gx_image3x_planes_wanted(const gx_image_enum_common_t * info,byte * wanted)7733ff48bf5SDavid du Colombier gx_image3x_planes_wanted(const gx_image_enum_common_t * info, byte *wanted)
7743ff48bf5SDavid du Colombier {
7753ff48bf5SDavid du Colombier const gx_image3x_enum_t * const penum = (const gx_image3x_enum_t *) info;
7763ff48bf5SDavid du Colombier /*
7773ff48bf5SDavid du Colombier * We always want at least as much of the mask(s) to be filled as the
7783ff48bf5SDavid du Colombier * pixel data.
7793ff48bf5SDavid du Colombier */
7803ff48bf5SDavid du Colombier bool
7813ff48bf5SDavid du Colombier sso = penum->mask[0].InterleaveType == interleave_separate_source,
7823ff48bf5SDavid du Colombier sss = penum->mask[1].InterleaveType == interleave_separate_source;
7833ff48bf5SDavid du Colombier
7843ff48bf5SDavid du Colombier if (sso & sss) {
7853ff48bf5SDavid du Colombier /* Both masks have separate sources. */
7863ff48bf5SDavid du Colombier int mask_next = channel_next(&penum->mask[1], &penum->pixel);
7873ff48bf5SDavid du Colombier
7883ff48bf5SDavid du Colombier memset(wanted + 2, (mask_next <= 0 ? 0xff : 0), info->num_planes - 2);
7893ff48bf5SDavid du Colombier wanted[1] = (mask_next >= 0 ? 0xff : 0);
7903ff48bf5SDavid du Colombier if (wanted[1]) {
7913ff48bf5SDavid du Colombier mask_next = channel_next(&penum->mask[0], &penum->mask[1]);
7923ff48bf5SDavid du Colombier wanted[0] = mask_next >= 0;
7933ff48bf5SDavid du Colombier } else
7943ff48bf5SDavid du Colombier wanted[0] = 0;
7953ff48bf5SDavid du Colombier return false; /* see below */
7963ff48bf5SDavid du Colombier } else if (sso | sss) {
7973ff48bf5SDavid du Colombier /* Only one separate source. */
7983ff48bf5SDavid du Colombier const image3x_channel_state_t *pics =
7993ff48bf5SDavid du Colombier (sso ? &penum->mask[0] : &penum->mask[1]);
8003ff48bf5SDavid du Colombier int mask_next = channel_next(pics, &penum->pixel);
8013ff48bf5SDavid du Colombier
8023ff48bf5SDavid du Colombier wanted[0] = (mask_next >= 0 ? 0xff : 0);
8033ff48bf5SDavid du Colombier memset(wanted + 1, (mask_next <= 0 ? 0xff : 0), info->num_planes - 1);
8043ff48bf5SDavid du Colombier /*
8053ff48bf5SDavid du Colombier * In principle, wanted will always be true for both mask and pixel
8063ff48bf5SDavid du Colombier * data if the full_heights are equal. Unfortunately, even in this
8073ff48bf5SDavid du Colombier * case, processing may be interrupted after a mask row has been
8083ff48bf5SDavid du Colombier * passed to the underlying image processor but before the data row
8093ff48bf5SDavid du Colombier * has been passed, in which case pixel data will be 'wanted', but
8103ff48bf5SDavid du Colombier * not mask data, for the next call. Therefore, we must return
8113ff48bf5SDavid du Colombier * false.
8123ff48bf5SDavid du Colombier */
8133ff48bf5SDavid du Colombier return false
8143ff48bf5SDavid du Colombier /*(next == 0 &&
8153ff48bf5SDavid du Colombier pics->full_height == penum->pixel.full_height)*/;
8163ff48bf5SDavid du Colombier } else {
8173ff48bf5SDavid du Colombier /* Everything is chunky, only 1 plane. */
8183ff48bf5SDavid du Colombier wanted[0] = 0xff;
8193ff48bf5SDavid du Colombier return true;
8203ff48bf5SDavid du Colombier }
8213ff48bf5SDavid du Colombier }
8223ff48bf5SDavid du Colombier
8233ff48bf5SDavid du Colombier /* Clean up after processing an ImageType 3x image. */
8243ff48bf5SDavid du Colombier private int
gx_image3x_end_image(gx_image_enum_common_t * info,bool draw_last)8253ff48bf5SDavid du Colombier gx_image3x_end_image(gx_image_enum_common_t * info, bool draw_last)
8263ff48bf5SDavid du Colombier {
8273ff48bf5SDavid du Colombier gx_image3x_enum_t *penum = (gx_image3x_enum_t *) info;
8283ff48bf5SDavid du Colombier gs_memory_t *mem = penum->memory;
8293ff48bf5SDavid du Colombier gx_device *mdev0 = penum->mask[0].mdev;
8303ff48bf5SDavid du Colombier int ocode =
8313ff48bf5SDavid du Colombier (penum->mask[0].info ? gx_image_end(penum->mask[0].info, draw_last) :
8323ff48bf5SDavid du Colombier 0);
8333ff48bf5SDavid du Colombier gx_device *mdev1 = penum->mask[1].mdev;
8343ff48bf5SDavid du Colombier int scode =
8353ff48bf5SDavid du Colombier (penum->mask[1].info ? gx_image_end(penum->mask[1].info, draw_last) :
8363ff48bf5SDavid du Colombier 0);
8373ff48bf5SDavid du Colombier gx_device *pcdev = penum->pcdev;
8383ff48bf5SDavid du Colombier int pcode = gx_image_end(penum->pixel.info, draw_last);
8393ff48bf5SDavid du Colombier
8403ff48bf5SDavid du Colombier gs_closedevice(pcdev);
8413ff48bf5SDavid du Colombier if (mdev0)
8423ff48bf5SDavid du Colombier gs_closedevice(mdev0);
8433ff48bf5SDavid du Colombier if (mdev1)
8443ff48bf5SDavid du Colombier gs_closedevice(mdev1);
8453ff48bf5SDavid du Colombier gs_free_object(mem, penum->mask[0].data,
8463ff48bf5SDavid du Colombier "gx_image3x_end_image(mask[0].data)");
8473ff48bf5SDavid du Colombier gs_free_object(mem, penum->mask[1].data,
8483ff48bf5SDavid du Colombier "gx_image3x_end_image(mask[1].data)");
8493ff48bf5SDavid du Colombier gs_free_object(mem, penum->pixel.data,
8503ff48bf5SDavid du Colombier "gx_image3x_end_image(pixel.data)");
8513ff48bf5SDavid du Colombier gs_free_object(mem, pcdev, "gx_image3x_end_image(pcdev)");
8523ff48bf5SDavid du Colombier gs_free_object(mem, mdev0, "gx_image3x_end_image(mask[0].mdev)");
8533ff48bf5SDavid du Colombier gs_free_object(mem, mdev1, "gx_image3x_end_image(mask[1].mdev)");
8543ff48bf5SDavid du Colombier gs_free_object(mem, penum, "gx_image3x_end_image");
8553ff48bf5SDavid du Colombier return (pcode < 0 ? pcode : scode < 0 ? scode : ocode);
8563ff48bf5SDavid du Colombier }
857