/* Copyright (C) 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gxp1fill.c,v 1.2.6.1.2.1 2003/01/17 00:49:04 giles Exp $ */ /* PatternType 1 filling algorithms */ #include "math_.h" #include "gx.h" #include "gserrors.h" #include "gsrop.h" #include "gsmatrix.h" #include "gxcspace.h" /* for gscolor2.h */ #include "gxcolor2.h" #include "gxdcolor.h" #include "gxdevcli.h" #include "gxdevmem.h" #include "gxclip2.h" #include "gxpcolor.h" #include "gxp1impl.h" /* Define the state for tile filling. */ typedef struct tile_fill_state_s { /* Original arguments */ const gx_device_color *pdevc; /* pattern color */ int x0, y0, w0, h0; gs_logical_operation_t lop; const gx_rop_source_t *source; /* Variables set at initialization */ gx_device_tile_clip cdev; gx_device *pcdev; /* original device or &cdev */ const gx_strip_bitmap *tmask; gs_int_point phase; /* Following are only for uncolored patterns */ dev_color_proc_fill_rectangle((*fill_rectangle)); /* Following are only for colored patterns */ const gx_rop_source_t *rop_source; gx_device *orig_dev; int xoff, yoff; /* set dynamically */ } tile_fill_state_t; /* Initialize the filling state. */ private int tile_fill_init(tile_fill_state_t * ptfs, const gx_device_color * pdevc, gx_device * dev, bool set_mask_phase) { gx_color_tile *m_tile = pdevc->mask.m_tile; int px, py; ptfs->pdevc = pdevc; if (m_tile == 0) { /* no clipping */ ptfs->pcdev = dev; ptfs->phase = pdevc->phase; return 0; } ptfs->pcdev = (gx_device *) & ptfs->cdev; ptfs->tmask = &m_tile->tmask; ptfs->phase.x = pdevc->mask.m_phase.x; ptfs->phase.y = pdevc->mask.m_phase.y; /* * For non-simple tiles, the phase will be reset on each pass of the * tile_by_steps loop, but for simple tiles, we must set it now. */ if (set_mask_phase && m_tile->is_simple) { px = imod(-(int)(m_tile->step_matrix.tx - ptfs->phase.x + 0.5), m_tile->tmask.rep_width); py = imod(-(int)(m_tile->step_matrix.ty - ptfs->phase.y + 0.5), m_tile->tmask.rep_height); } else px = py = 0; return tile_clip_initialize(&ptfs->cdev, ptfs->tmask, dev, px, py, NULL); } /* * Fill with non-standard X and Y stepping. * ptile is pdevc->colors.pattern.{m,p}_tile. * tbits_or_tmask is whichever of tbits and tmask is supplying * the tile size. * This implementation could be sped up considerably! */ private int tile_by_steps(tile_fill_state_t * ptfs, int x0, int y0, int w0, int h0, const gx_color_tile * ptile, const gx_strip_bitmap * tbits_or_tmask, int (*fill_proc) (P5(const tile_fill_state_t * ptfs, int x, int y, int w, int h))) { int x1 = x0 + w0, y1 = y0 + h0; int i0, i1, j0, j1, i, j; gs_matrix step_matrix; /* translated by phase */ int code; ptfs->x0 = x0, ptfs->w0 = w0; ptfs->y0 = y0, ptfs->h0 = h0; step_matrix = ptile->step_matrix; step_matrix.tx -= ptfs->phase.x; step_matrix.ty -= ptfs->phase.y; { gs_rect bbox; /* bounding box in device space */ gs_rect ibbox; /* bounding box in stepping space */ double bbw = ptile->bbox.q.x - ptile->bbox.p.x; double bbh = ptile->bbox.q.y - ptile->bbox.p.y; double u0, v0, u1, v1; bbox.p.x = x0, bbox.p.y = y0; bbox.q.x = x1, bbox.q.y = y1; gs_bbox_transform_inverse(&bbox, &step_matrix, &ibbox); if_debug10('T', "[T]x,y=(%d,%d) w,h=(%d,%d) => (%g,%g),(%g,%g), offset=(%g,%g)\n", x0, y0, w0, h0, ibbox.p.x, ibbox.p.y, ibbox.q.x, ibbox.q.y, step_matrix.tx, step_matrix.ty); /* * If the pattern is partly transparent and XStep/YStep is smaller * than the device space BBox, we need to ensure that we cover * each pixel of the rectangle being filled with *every* pattern * that overlaps it, not just *some* pattern copy. */ u0 = ibbox.p.x - max(ptile->bbox.p.x, 0) - 0.000001; v0 = ibbox.p.y - max(ptile->bbox.p.y, 0) - 0.000001; u1 = ibbox.q.x - min(ptile->bbox.q.x, 0) + 0.000001; v1 = ibbox.q.y - min(ptile->bbox.q.y, 0) + 0.000001; if (!ptile->is_simple) u0 -= bbw, v0 -= bbh, u1 += bbw, v1 += bbh; i0 = (int)floor(u0); j0 = (int)floor(v0); i1 = (int)ceil(u1); j1 = (int)ceil(v1); } if_debug4('T', "[T]i=(%d,%d) j=(%d,%d)\n", i0, i1, j0, j1); for (i = i0; i < i1; i++) for (j = j0; j < j1; j++) { int x = (int)(step_matrix.xx * i + step_matrix.yx * j + step_matrix.tx); int y = (int)(step_matrix.xy * i + step_matrix.yy * j + step_matrix.ty); int w = tbits_or_tmask->size.x; int h = tbits_or_tmask->size.y; int xoff, yoff; if_debug4('T', "[T]i=%d j=%d x,y=(%d,%d)", i, j, x, y); if (x < x0) xoff = x0 - x, x = x0, w -= xoff; else xoff = 0; if (y < y0) yoff = y0 - y, y = y0, h -= yoff; else yoff = 0; if (x + w > x1) w = x1 - x; if (y + h > y1) h = y1 - y; if_debug6('T', "=>(%d,%d) w,h=(%d,%d) x/yoff=(%d,%d)\n", x, y, w, h, xoff, yoff); if (w > 0 && h > 0) { if (ptfs->pcdev == (gx_device *) & ptfs->cdev) tile_clip_set_phase(&ptfs->cdev, imod(xoff - x, ptfs->tmask->rep_width), imod(yoff - y, ptfs->tmask->rep_height)); /* Set the offsets for colored pattern fills */ ptfs->xoff = xoff; ptfs->yoff = yoff; code = (*fill_proc) (ptfs, x, y, w, h); if (code < 0) return code; } } return 0; } /* Fill a rectangle with a colored Pattern. */ /* Note that we treat this as "texture" for RasterOp. */ private int tile_colored_fill(const tile_fill_state_t * ptfs, int x, int y, int w, int h) { gx_color_tile *ptile = ptfs->pdevc->colors.pattern.p_tile; gs_logical_operation_t lop = ptfs->lop; const gx_rop_source_t *source = ptfs->source; const gx_rop_source_t *rop_source = ptfs->rop_source; gx_device *dev = ptfs->orig_dev; int xoff = ptfs->xoff, yoff = ptfs->yoff; gx_strip_bitmap *bits = &ptile->tbits; const byte *data = bits->data; bool full_transfer = (w == ptfs->w0 && h == ptfs->h0); gx_bitmap_id source_id = (full_transfer ? rop_source->id : gx_no_bitmap_id); int code; if (source == NULL && lop_no_S_is_T(lop)) code = (*dev_proc(ptfs->pcdev, copy_color)) (ptfs->pcdev, data + bits->raster * yoff, xoff, bits->raster, (full_transfer ? bits->id : gx_no_bitmap_id), x, y, w, h); else { gx_strip_bitmap data_tile; data_tile.data = (byte *) data; /* actually const */ data_tile.raster = bits->raster; data_tile.size.x = data_tile.rep_width = ptile->tbits.size.x; data_tile.size.y = data_tile.rep_height = ptile->tbits.size.y; data_tile.id = bits->id; data_tile.shift = data_tile.rep_shift = 0; code = (*dev_proc(dev, strip_copy_rop)) (dev, rop_source->sdata + (y - ptfs->y0) * rop_source->sraster, rop_source->sourcex + (x - ptfs->x0), rop_source->sraster, source_id, (rop_source->use_scolors ? rop_source->scolors : NULL), &data_tile, NULL, x, y, w, h, imod(xoff - x, data_tile.rep_width), imod(yoff - y, data_tile.rep_height), lop); } return code; } int gx_dc_pattern_fill_rectangle(const gx_device_color * pdevc, int x, int y, int w, int h, gx_device * dev, gs_logical_operation_t lop, const gx_rop_source_t * source) { gx_color_tile *ptile = pdevc->colors.pattern.p_tile; const gx_rop_source_t *rop_source = source; gx_rop_source_t no_source; gx_strip_bitmap *bits; tile_fill_state_t state; int code; if (ptile == 0) /* null pattern */ return 0; if (rop_source == NULL) set_rop_no_source(rop_source, no_source, dev); bits = &ptile->tbits; code = tile_fill_init(&state, pdevc, dev, false); if (code < 0) return code; if (ptile->is_simple) { int px = imod(-(int)(ptile->step_matrix.tx - state.phase.x + 0.5), bits->rep_width); int py = imod(-(int)(ptile->step_matrix.ty - state.phase.y + 0.5), bits->rep_height); if (state.pcdev != dev) tile_clip_set_phase(&state.cdev, px, py); if (source == NULL && lop_no_S_is_T(lop)) code = (*dev_proc(state.pcdev, strip_tile_rectangle)) (state.pcdev, bits, x, y, w, h, gx_no_color_index, gx_no_color_index, px, py); else code = (*dev_proc(state.pcdev, strip_copy_rop)) (state.pcdev, rop_source->sdata, rop_source->sourcex, rop_source->sraster, rop_source->id, (rop_source->use_scolors ? rop_source->scolors : NULL), bits, NULL, x, y, w, h, px, py, lop); } else { state.lop = lop; state.source = source; state.rop_source = rop_source; state.orig_dev = dev; code = tile_by_steps(&state, x, y, w, h, ptile, &ptile->tbits, tile_colored_fill); } return code; } /* Fill a rectangle with an uncolored Pattern. */ /* Note that we treat this as "texture" for RasterOp. */ private int tile_masked_fill(const tile_fill_state_t * ptfs, int x, int y, int w, int h) { if (ptfs->source == NULL) return (*ptfs->fill_rectangle) (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, NULL); else { const gx_rop_source_t *source = ptfs->source; gx_rop_source_t step_source; step_source.sdata = source->sdata + (y - ptfs->y0) * source->sraster; step_source.sourcex = source->sourcex + (x - ptfs->x0); step_source.sraster = source->sraster; step_source.id = (w == ptfs->w0 && h == ptfs->h0 ? source->id : gx_no_bitmap_id); step_source.scolors[0] = source->scolors[0]; step_source.scolors[1] = source->scolors[1]; step_source.use_scolors = source->use_scolors; return (*ptfs->fill_rectangle) (ptfs->pdevc, x, y, w, h, ptfs->pcdev, ptfs->lop, &step_source); } } int gx_dc_pure_masked_fill_rect(const gx_device_color * pdevc, int x, int y, int w, int h, gx_device * dev, gs_logical_operation_t lop, const gx_rop_source_t * source) { gx_color_tile *ptile = pdevc->mask.m_tile; tile_fill_state_t state; int code; /* * This routine should never be called if there is no masking, * but we leave the checks below just in case. */ code = tile_fill_init(&state, pdevc, dev, true); if (code < 0) return code; if (state.pcdev == dev || ptile->is_simple) return (*gx_dc_type_data_pure.fill_rectangle) (pdevc, x, y, w, h, state.pcdev, lop, source); else { state.lop = lop; state.source = source; state.fill_rectangle = gx_dc_type_data_pure.fill_rectangle; return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask, tile_masked_fill); } } int gx_dc_binary_masked_fill_rect(const gx_device_color * pdevc, int x, int y, int w, int h, gx_device * dev, gs_logical_operation_t lop, const gx_rop_source_t * source) { gx_color_tile *ptile = pdevc->mask.m_tile; tile_fill_state_t state; int code; code = tile_fill_init(&state, pdevc, dev, true); if (code < 0) return code; if (state.pcdev == dev || ptile->is_simple) return (*gx_dc_type_data_ht_binary.fill_rectangle) (pdevc, x, y, w, h, state.pcdev, lop, source); else { state.lop = lop; state.source = source; state.fill_rectangle = gx_dc_type_data_ht_binary.fill_rectangle; return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask, tile_masked_fill); } } int gx_dc_colored_masked_fill_rect(const gx_device_color * pdevc, int x, int y, int w, int h, gx_device * dev, gs_logical_operation_t lop, const gx_rop_source_t * source) { gx_color_tile *ptile = pdevc->mask.m_tile; tile_fill_state_t state; int code; code = tile_fill_init(&state, pdevc, dev, true); if (code < 0) return code; if (state.pcdev == dev || ptile->is_simple) return (*gx_dc_type_data_ht_colored.fill_rectangle) (pdevc, x, y, w, h, state.pcdev, lop, source); else { state.lop = lop; state.source = source; state.fill_rectangle = gx_dc_type_data_ht_colored.fill_rectangle; return tile_by_steps(&state, x, y, w, h, ptile, &ptile->tmask, tile_masked_fill); } }