/* * Convert a CIEBasedDEF color into device color. */ static int client_remap_CIEBasedDEF(client_custom_color_params_t * pparams, const gs_client_color * pc, const gs_color_space * pcs, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { demo_color_space_data_t * pdata = (demo_color_space_data_t *)(pcs->pclient_color_space_data); frac rgb[3]; int i; /*** Demonstrate method to convert to XYZ ***/ if (pdata->CIEtoXYZ_pis) { frac xyz[3]; cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pis); /* We don't really do anything with these values, but this */ /* is where a real client could convert to a device color */ if_debug6('|', "[c]client_remap CIEDEF [%g, %g, %g] -> XYZ [%g, %g, %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2], frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2])); } /* * For demo and debug purposes, make our colors a function of the * intensity of the given color value and the object type. The color * values could represent almost anything. However we are assuming * that they are RGB values. */ for (i = 0; i < 3; i++) rgb[i] = convert2frac(pc->paint.values[i], pcs->params.def->RangeDEF.ranges[i]); return client_remap_DeviceRGB(pparams, rgb, pcs, pdc, pis, dev, select); }
static void debug_b_print_matrix(const gs_pixel_image_t *pim) { if_debug6('b', " ImageMatrix=[%g %g %g %g %g %g]\n", pim->ImageMatrix.xx, pim->ImageMatrix.xy, pim->ImageMatrix.yx, pim->ImageMatrix.yy, pim->ImageMatrix.tx, pim->ImageMatrix.ty); }
/* * Convert a ICCBased color into device color. */ static int client_remap_ICCBased(client_custom_color_params_t * pparams, const gs_client_color * pc, const gs_color_space * pcs, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { demo_color_space_data_t * pdata = (demo_color_space_data_t *)(pcs->pclient_color_space_data); frac frac_color[GS_CLIENT_COLOR_MAX_COMPONENTS]; int i, num_values = pcs->params.icc.picc_info->num_components; /*** Demonstrate method to convert to XYZ ***/ if (pdata->CIEtoXYZ_pis) { frac xyz[3]; cs_concretize_color(pc, pcs, xyz, pdata->CIEtoXYZ_pis); /* We don't really do anything with these values, but this */ /* is where a real client could convert to a device color */ if_debug6('|', "[c]client_remap ICCBased [%g, %g, %g] -> XYZ [%g, %g, %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2], frac2float(xyz[0]), frac2float(xyz[1]), frac2float(xyz[2])); } /* * For demo and debug purposes, make our colors a function of the * intensity of the given color value and the object type. The color * values could represent almost anything. However based upon the * number of color values, we are assuming that they are either * gray, RGB, or CMYK values. */ for (i = 0; i < num_values; i++) frac_color[i] = convert2frac(pc->paint.values[i], pcs->params.icc.picc_info->Range.ranges[i]); switch (num_values) { case 0: case 2: return_error(gs_error_rangecheck); case 1: return client_remap_DeviceGray(pparams, frac_color, pcs, pdc, pis, dev, select); case 3: return client_remap_DeviceRGB(pparams, frac_color, pcs, pdc, pis, dev, select); case 4: default: return client_remap_DeviceCMYK(pparams, frac_color, pcs, pdc, pis, dev, select); } }
static int tag_dispatch_90X1(px_args_t * par, px_state_t * pxs) { px_vendor_state_t *v_state = pxs->vendor_state; int code = 0; for (;;) { uint32_t old_avail = par->source.available; switch (v_state->tag.tag_id) { case 0x9031: code = read_mode10_bitmap_data(&(v_state->row), par, pxs, true); break; case 0x9011: code = read_mode10_bitmap_data(&(v_state->row), par, pxs, false); break; case 0x9021: code = read_headless_jpeg_bitmap_data(&(v_state->row), par, pxs); break; } v_state->tag.bytes_so_far += old_avail - par->source.available; if_debug6('I', "new src.p %lu old.avail %u new.avail %u bytes=%d/%d code %d\n", par->source.position, old_avail, par->source.available, v_state->tag.bytes_so_far, v_state->tag.bytes_expected, code); if (code < 0) return_error(errorIllegalDataValue); if ((code == pxNeedData) && (v_state->tag.bytes_so_far >= v_state->tag.bytes_expected)) return_error(errorIllegalDataValue); /* 3550's behavior */ if (code != 1) /* = 0 */ return code; code = pl_image_data(pxs->pgs, v_state->info, (const byte **)&(v_state->row), 0, v_state->data_per_row, 1); if (code < 0) return code; pxs->have_page = true; } /* unreachable */ return code; }
/* * This is somewhat a clone of the tile_by_steps function but one * that performs filling from and to pdf14dev (transparency) buffers. * At some point it may be desirable to do some optimization here. */ static int tile_by_steps_trans(tile_fill_trans_state_t * ptfs, int x0, int y0, int w0, int h0, gx_pattern_trans_t *fill_trans_buffer, const gx_color_tile * ptile) { int x1 = x0 + w0, y1 = y0 + h0; int i0, i1, j0, j1, i, j; gs_matrix step_matrix; /* translated by phase */ gx_pattern_trans_t *ptrans_pat = ptile->ttrans; 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)fastfloor(u0); j0 = (int)fastfloor(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)fastfloor(step_matrix.xx * i + step_matrix.yx * j + step_matrix.tx); int y = (int)fastfloor(step_matrix.xy * i + step_matrix.yy * j + step_matrix.ty); int w = ptrans_pat->width; int h = ptrans_pat->height; int xoff, yoff; int px, py; 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) { px = imod(xoff - x, ptile->ttrans->width); py = imod(yoff - y, ptile->ttrans->height); /* Set the offsets for colored pattern fills */ ptfs->xoff = xoff; ptfs->yoff = yoff; /* We only go through blending during tiling, if there was overlap as defined by the step matrix and the bounding box */ ptile->ttrans->pat_trans_fill(x, y, x+w, y+h, px, py, ptile, fill_trans_buffer); } } return 0; }
/* * 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! */ static 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) (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)fastfloor(u0); j0 = (int)fastfloor(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)fastfloor(step_matrix.xx * i + step_matrix.yx * j + step_matrix.tx); int y = (int)fastfloor(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; }
void eprn_get_initial_matrix(gx_device *device, gs_matrix *mptr) { eprn_Device *dev = (eprn_Device *)device; float /* The following two arrays are oriented w.r.t. pixmap device space, i.e., the index 0 refers to the x coordinate (horizontal) and the index 1 to the y coordinate (vertical) in pixmap device space. */ extension[2], /* media extension in pixels */ pixels_per_bp[2]; /* resolution */ int j, quarters; #ifdef EPRN_TRACE if_debug0(EPRN_TRACE_CHAR, "! eprn_get_initial_matrix()...\n"); #endif /* We need 'default_orientation' and also the margins. */ if (dev->eprn.code == ms_none) { #ifdef EPRN_TRACE if_debug0(EPRN_TRACE_CHAR, "! eprn_get_initial_matrix(): code is still ms_none.\n"); #endif if (eprn_set_page_layout(dev) != 0) eprintf(" Processing can't be stopped at this point although this error " "occurred.\n"); /* The current function has a signature without the ability to signal an error condition. */ } quarters = dev->eprn.default_orientation + (dev->MediaSize[0] <= dev->MediaSize[1]? 0: 1); /* Number of quarter-circle rotations by +90 degrees necessary to obtain default user space starting with the y axis upwards in pixmap device space. It's not documented, but 'MediaSize' is the requested "PageSize" page device parameter value and hence is to be interpreted in default (not default default!) user space. The condition above therefore tests whether landscape orientation has been requested. */ /* Soft tumble option: rotate default user space by 180 degrees on every second page */ if (dev->eprn.soft_tumble && dev->ShowpageCount % 2 != 0) quarters += 2; /* Prepare auxiliary data */ for (j = 0; j < 2; j++) pixels_per_bp[j] = dev->HWResolution[j]/BP_PER_IN; /* 'HWResolution[]' contains the standard PostScript page device parameter 'HWResolution' which is defined in pixels per inch with respect to device space. */ if (quarters % 2 == 0) { /* Default user space and pixmap device space agree in what is "horizontal" and what is "vertical". */ extension[0] = dev->MediaSize[0]; extension[1] = dev->MediaSize[1]; } else { extension[0] = dev->MediaSize[1]; extension[1] = dev->MediaSize[0]; } /* Convert from bp to pixels: */ for (j = 0; j < 2; j++) extension[j] *= pixels_per_bp[j]; /* Note that we are using the user-specified extension of the sheet, not the "official" one we could obtain in most cases from 'size'. */ switch (quarters % 4) { case 0: /* The y axis of default user space points upwards in pixmap device space. The CTM is uniquely characterized by the following mappings from default user space to pixmap device space: (0, 0) -> (0, height in pixels) (width in bp, 0) -> (width in pixels, height in pixels) (0, height in bp) -> (0, 0) 'width' and 'height' refer to the sheet's extension as seen from pixmap device space, i.e., width in pixels == extension[0] and height in pixels == extension[1]. From the PLR we find that the CTM is a PostScript matrix [a b c d tx ty] used for mapping user space coordinates (x, y) to device space coordinates (x', y') as follows: x' = a*x + c*y + tx y' = b*x + d*y + ty Ghostscript's matrix type 'gs_matrix' writes its structure components 'xx' etc. in storage layout order into a PostScript matrix (see write_matrix() in iutil.c), hence we obtain by comparison with gsmatrix.h the PostScript matrix [ xx xy yx yy tx ty ]. The correspondence can also be seen by comparison of the equations above with the code in gs_point_transform() in gsmatrix.c. It would, however, still be reassuring to have a corresponding statement in ghostscript's documentation. */ gx_default_get_initial_matrix(device, mptr); /* Of course, I could also set this directly: mptr->xx = pixels_per_bp[0]; mptr->xy = 0; mptr->yx = 0; mptr->yy = -pixels_per_bp[1]; mptr->tx = 0; mptr->ty = extension[1]; Doing it in this way is, however, more stable against dramatic changes in ghostscript. */ break; case 1: /* The y axis of default user space points to the left in pixmap device space. The CTM is uniquely characterized by the following mappings from default user space to pixmap device space: (0, 0) -> (width in pixels, height in pixels) (height in bp, 0) -> (width in pixels, 0) (0, width in bp) -> (0, height in pixels) */ mptr->xx = 0; mptr->xy = -pixels_per_bp[1]; mptr->yx = -pixels_per_bp[0]; mptr->yy = 0; mptr->tx = extension[0]; mptr->ty = extension[1]; break; case 2: /* The y axis of default user space points downwards in pixmap device space. The CTM is uniquely characterized by the following mappings from default user space to pixmap device space: (0, 0) -> (width in pixels, 0) (width in bp, 0) -> (0, 0) (0, height in bp) -> (width in pixels, height in pixels) */ mptr->xx = -pixels_per_bp[0]; mptr->xy = 0; mptr->yx = 0; mptr->yy = pixels_per_bp[1]; mptr->tx = extension[0]; mptr->ty = 0; break; case 3: /* The y axis of default user space points to the right in pixmap device space. The CTM is uniquely characterized by the following mappings from default user space to pixmap device space: (0, 0) -> (0, 0) (height in bp, 0) -> (0, height in pixels) (0, width in bp) -> (width in pixels, 0) */ mptr->xx = 0; mptr->xy = pixels_per_bp[1]; mptr->yx = pixels_per_bp[0]; mptr->yy = 0; mptr->tx = 0; mptr->ty = 0; break; } /* Finally, shift the device space origin to the top-left corner of the printable area. I am deliberately not using the corresponding shift feature in gx_device_set_margins() because it achieves its effect by using the 'Margins' array which should remain at the user's disposal for correcting misadjustments. In addition, gx_device_set_margins() will not work correctly for quarters % 4 != 0 anyway. */ { gs_matrix translation; /* Translation of pixmap device space origin by top and left margins in pixmap device space */ gs_make_translation( -dev->eprn.right_shift*pixels_per_bp[0], -dev->eprn.down_shift *pixels_per_bp[1], &translation); /* Multiply the initial matrix from the right with the translation matrix, i.e., in going from user to device space the translation will be applied last. */ gs_matrix_multiply(mptr, &translation, mptr); } #ifdef EPRN_TRACE if_debug6(EPRN_TRACE_CHAR, " Returning [%g %g %g %g %g %g].\n", mptr->xx, mptr->xy, mptr->yx, mptr->yy, mptr->tx, mptr->ty); #endif return; }
/* this procedure is exported for the benefit of gsicc.c */ int gx_cie_real_remap_finish(cie_cached_vector3 vec3, frac * pconc, const gs_imager_state * pis, const gs_color_space *pcs) { const gs_cie_render *pcrd = pis->cie_render; const gx_cie_joint_caches *pjc = pis->cie_joint_caches; const gs_const_string *table = pcrd->RenderTable.lookup.table; int tabc[3]; /* indices for final EncodeABC lookup */ /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */ if (!pjc->skipDecodeLMN) cie_lookup_map3(&vec3 /* LMN => PQR */, &pjc->DecodeLMN, "Decode/MatrixLMN+MatrixPQR"); /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */ if (!pjc->skipPQR) cie_lookup_map3(&vec3 /* PQR => LMN */, &pjc->TransformPQR, "Transform/Matrix'PQR+MatrixLMN"); /* Apply EncodeLMN and MatrixABC(encode). */ if (!pjc->skipEncodeLMN) cie_lookup_map3(&vec3 /* LMN => ABC */, &pcrd->caches.EncodeLMN, "EncodeLMN+MatrixABC"); /* MatrixABCEncode includes the scaling of the EncodeABC */ /* cache index. */ #define SET_TABC(i, t)\ BEGIN\ tabc[i] = cie_cached2int(vec3 /*ABC*/.t - pcrd->EncodeABC_base[i],\ _cie_interpolate_bits);\ if ((uint)tabc[i] > (gx_cie_cache_size - 1) << _cie_interpolate_bits)\ tabc[i] = (tabc[i] < 0 ? 0 :\ (gx_cie_cache_size - 1) << _cie_interpolate_bits);\ END SET_TABC(0, u); SET_TABC(1, v); SET_TABC(2, w); #undef SET_TABC if (table == 0) { /* * No further transformation. * The final mapping step includes both restriction to * the range [0..1] and conversion to fracs. */ #define EABC(i)\ cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.fracs.values, tabc[i]) pconc[0] = EABC(0); pconc[1] = EABC(1); pconc[2] = EABC(2); #undef EABC return 3; } else { /* * Use the RenderTable. */ int m = pcrd->RenderTable.lookup.m; #define RT_LOOKUP(j, i) pcrd->caches.RenderTableT[j].fracs.values[i] #ifdef CIE_RENDER_TABLE_INTERPOLATE /* * The final mapping step includes restriction to the * ranges [0..dims[c]] as ints with interpolation bits. */ fixed rfix[3]; const int s = _fixed_shift - _cie_interpolate_bits; #define EABC(i)\ cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.ints.values, tabc[i]) #define FABC(i, s)\ ((s) > 0) ? (EABC(i) << (s)) : (EABC(i) >> -(s)) rfix[0] = FABC(0, s); rfix[1] = FABC(1, s); rfix[2] = FABC(2, s); #undef FABC #undef EABC if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n", cie_cached2float(vec3.u), cie_cached2float(vec3.v), cie_cached2float(vec3.w), fixed2float(rfix[0]), fixed2float(rfix[1]), fixed2float(rfix[2])); gx_color_interpolate_linear(rfix, &pcrd->RenderTable.lookup, pconc); if_debug3('c', "[c] interpolated => %g,%g,%g\n", frac2float(pconc[0]), frac2float(pconc[1]), frac2float(pconc[2])); if (!pcrd->caches.RenderTableT_is_identity) { /* Map the interpolated values. */ #define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size) pconc[0] = RT_LOOKUP(0, frac2cache_index(pconc[0])); pconc[1] = RT_LOOKUP(1, frac2cache_index(pconc[1])); pconc[2] = RT_LOOKUP(2, frac2cache_index(pconc[2])); if (m > 3) pconc[3] = RT_LOOKUP(3, frac2cache_index(pconc[3])); #undef frac2cache_index } #else /* !CIE_RENDER_TABLE_INTERPOLATE */ /* * The final mapping step includes restriction to the ranges * [0..dims[c]], plus scaling of the indices in the strings. */ #define RI(i)\ pcrd->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits] int ia = RI(0); int ib = RI(1); /* pre-multiplied by m * NC */ int ic = RI(2); /* pre-multiplied by m */ const byte *prtc = table[ia].data + ib + ic; /* (*pcrd->RenderTable.T)(prtc, m, pcrd, pconc); */ if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n", cie_cached2float(vec3.u), cie_cached2float(vec3.v), cie_cached2float(vec3.w), ia, ib, ic); if (pcrd->caches.RenderTableT_is_identity) { pconc[0] = byte2frac(prtc[0]); pconc[1] = byte2frac(prtc[1]); pconc[2] = byte2frac(prtc[2]); if (m > 3) pconc[3] = byte2frac(prtc[3]); } else { #if gx_cie_log2_cache_size == 8 # define byte2cache_index(b) (b) #else # if gx_cie_log2_cache_size > 8 # define byte2cache_index(b)\ ( ((b) << (gx_cie_log2_cache_size - 8)) +\ ((b) >> (16 - gx_cie_log2_cache_size)) ) # else /* < 8 */ # define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size)) # endif #endif pconc[0] = RT_LOOKUP(0, byte2cache_index(prtc[0])); pconc[1] = RT_LOOKUP(1, byte2cache_index(prtc[1])); pconc[2] = RT_LOOKUP(2, byte2cache_index(prtc[2])); if (m > 3) pconc[3] = RT_LOOKUP(3, byte2cache_index(prtc[3])); #undef byte2cache_index } #endif /* !CIE_RENDER_TABLE_INTERPOLATE */ #undef RI #undef RT_LOOKUP return m; } }
/* Process a buffer */ #define LINE_LIMIT 79 /* not 80, to satisfy Genoa FTS */ static int s_A85E_process(stream_state * st, stream_cursor_read * pr, stream_cursor_write * pw, bool last) { stream_A85E_state *const ss = (stream_A85E_state *) st; register const byte *p = pr->ptr; register byte *q = pw->ptr; byte *qn = q + (LINE_LIMIT - ss->count); /* value of q before next EOL */ const byte *rlimit = pr->limit; byte *wlimit = pw->limit; int status = 0; int prev = ss->last_char; int count; if_debug3('w', "[w85]initial ss->count = %d, rcount = %d, wcount = %d\n", ss->count, (int)(rlimit - p), (int)(wlimit - q)); for (; (count = rlimit - p) >= 4; p += 4) { ulong word = ((ulong) (((uint) p[1] << 8) + p[2]) << 16) + (((uint) p[3] << 8) + p[4]); if (word == 0) { if (q >= qn) { if (wlimit - q < 2) { status = 1; break; } *++q = prev = '\n'; qn = q + LINE_LIMIT; if_debug1('w', "[w85]EOL at %d bytes written\n", (int)(q - pw->ptr)); } else { if (q >= wlimit) { status = 1; break; } } *++q = prev = 'z'; } else { ulong v4 = word / 85; /* max 85^4 */ ulong v3 = v4 / 85; /* max 85^3 */ uint v2 = v3 / 85; /* max 85^2 */ uint v1 = v2 / 85; /* max 85 */ put: if (q + 5 > qn) { if (q >= wlimit) { status = 1; break; } *++q = prev = '\n'; qn = q + LINE_LIMIT; if_debug1('w', "[w85]EOL at %d bytes written\n", (int)(q - pw->ptr)); goto put; } if (wlimit - q < 5) { status = 1; break; } q[1] = (byte) v1 + '!'; q[2] = (byte) (v2 - v1 * 85) + '!'; q[3] = (byte) ((uint) v3 - v2 * 85) + '!'; q[4] = (byte) ((uint) v4 - (uint) v3 * 85) + '!'; q[5] = (byte) ((uint) word - (uint) v4 * 85) + '!'; /* * '%%' or '%!' at the beginning of the line will confuse some * document managers: insert (an) EOL(s) if necessary to prevent * this. */ if (q[1] == '%') { if (prev == '%') { if (qn - q == LINE_LIMIT - 1) { /* A line would begin with %%. */ *++q = prev = '\n'; qn = q + LINE_LIMIT; if_debug1('w', "[w85]EOL for %%%% at %d bytes written\n", (int)(q - pw->ptr)); goto put; } } else if (prev == '\n' && (q[2] == '%' || q[2] == '!')) { /* * We may have to insert more than one EOL if * there are more than two %s in a row. */ int extra = (q[2] == '!' ? 1 : /* else q[2] == '%' */ q[3] == '!' ? 2 : q[3] != '%' ? 1 : q[4] == '!' ? 3 : q[4] != '%' ? 2 : q[5] == '!' ? 4 : q[5] != '%' ? 3 : 4); if (wlimit - q < 5 + extra) { status = 1; break; } if_debug6('w', "[w]%c%c%c%c%c extra = %d\n", q[1], q[2], q[3], q[4], q[5], extra); switch (extra) { case 4: q[9] = q[5], q[8] = '\n'; goto e3; case 3: q[8] = q[5]; e3:q[7] = q[4], q[6] = '\n'; goto e2; case 2: q[7] = q[5], q[6] = q[4]; e2:q[5] = q[3], q[4] = '\n'; goto e1; case 1: q[6] = q[5], q[5] = q[4], q[4] = q[3]; e1:q[3] = q[2], q[2] = '\n'; } if_debug1('w', "[w85]EOL at %d bytes written\n", (int)(q + 2 * extra - pw->ptr)); qn = q + 2 * extra + LINE_LIMIT; q += extra; } } else if (q[1] == '!' && prev == '%' && qn - q == LINE_LIMIT - 1 ) { /* A line would begin with %!. */ *++q = prev = '\n'; qn = q + LINE_LIMIT; if_debug1('w', "[w85]EOL for %%! at %d bytes written\n", (int)(q - pw->ptr)); goto put; } prev = *(q += 5); } } end: ss->count = LINE_LIMIT - (qn - q); /* Check for final partial word. */ if (last && status == 0 && count < 4) { char buf[5]; int nchars = (count == 0 ? 2 : count + 3); ulong word = 0; ulong divisor = 85L * 85 * 85 * 85; int i, space; switch (count) { case 3: word += (uint) p[3] << 8; case 2: word += (ulong) p[2] << 16; case 1: word += (ulong) p[1] << 24; for(i=0; i <= count; i++) { ulong v = word / divisor; /* actually only a byte */ buf[i] = (byte) v + '!'; word -= v * divisor; divisor /= 85; } /*case 0: */ } space = count && buf[0] == '%' && ( (prev == '\n' && ( buf[1] == '%' || buf[1] =='!')) || (prev == '%' && qn - q == LINE_LIMIT - 1) ); if (wlimit - q < nchars+space) status = 1; else if (q + nchars+space > qn) { *++q = prev = '\n'; qn = q + LINE_LIMIT; goto end; } else { if (count) { if (space) *++q = ' '; memcpy(q+1, buf, count+1); q += count+1; p += count; } *++q = '~'; *++q = '>'; } } if_debug3('w', "[w85]final ss->count = %d, %d bytes read, %d written\n", ss->count, (int)(p - pr->ptr), (int)(q - pw->ptr)); pr->ptr = p; if (q > pw->ptr) ss->last_char = *q; pw->ptr = q; return status; }