/* Fill a rectangle with a color. */ static int x_fill_rectangle(gx_device * dev, int x, int y, int w, int h, gx_color_index gscolor) { gx_device_X *xdev = (gx_device_X *) dev; unsigned long color = (unsigned long) gscolor; fit_fill(dev, x, y, w, h); flush_text(xdev); X_SET_FILL_STYLE(xdev, FillSolid); X_SET_FORE_COLOR(xdev, color); X_SET_FUNCTION(xdev, GXcopy); XFillRectangle(xdev->dpy, xdev->dest, xdev->gc, x, y, w, h); /* If we are filling the entire screen, reset */ /* colors_or and colors_and. It's wasteful to test this */ /* on every operation, but there's no separate driver routine */ /* for erasepage (yet). */ if (x == 0 && y == 0 && w == xdev->width && h == xdev->height) { if (color == xdev->foreground || color == xdev->background) gdev_x_free_dynamic_colors(xdev); xdev->colors_or = xdev->colors_and = color; } if (xdev->bpixmap != (Pixmap) 0) { x_update_add(xdev, x, y, w, h); } if_debug5('F', "[F] fill (%d,%d):(%d,%d) %ld\n", x, y, w, h, (long)color); return 0; }
static void cie_lookup_map3(cie_cached_vector3 * pvec, const gx_cie_vector_cache3_t * pc, const char *cname) { if_debug5('c', "[c]lookup %s 0x%lx [%g %g %g]\n", (const char *)cname, (ulong) pc, cie_cached2float(pvec->u), cie_cached2float(pvec->v), cie_cached2float(pvec->w)); cie_lookup_mult3(pvec, pc); if_debug3('c', " =[%g %g %g]\n", cie_cached2float(pvec->u), cie_cached2float(pvec->v), cie_cached2float(pvec->w)); }
/* Tracing printout */ static void print_save(const char *str, uint spacen, const alloc_save_t *sav) { if_debug5('u', "[u]%s space %u 0x%lx: cdata = 0x%lx, id = %lu\n",\ str, spacen, (ulong)sav, (ulong)sav->client_data, (ulong)sav->id); }
int gs_image_next_planes(gs_image_enum * penum, gs_const_string *plane_data /*[num_planes]*/, uint *used /*[num_planes]*/) { const int num_planes = penum->num_planes; int i; int code = 0; #ifdef DEBUG vd_get_dc('i'); vd_set_shift(0, 0); vd_set_scale(0.01); vd_set_origin(0, 0); if (gs_debug_c('b')) { int pi; for (pi = 0; pi < num_planes; ++pi) dprintf6("[b]plane %d source=0x%lx,%u pos=%u data=0x%lx,%u\n", pi, (ulong)penum->planes[pi].source.data, penum->planes[pi].source.size, penum->planes[pi].pos, (ulong)plane_data[pi].data, plane_data[pi].size); } #endif for (i = 0; i < num_planes; ++i) { used[i] = 0; if (penum->wanted[i] && plane_data[i].size != 0) { penum->planes[i].source.size = plane_data[i].size; penum->planes[i].source.data = plane_data[i].data; } } for (;;) { /* If wanted can vary, only transfer 1 row at a time. */ int h = (penum->wanted_varies ? 1 : max_int); /* Move partial rows from source[] to row[]. */ for (i = 0; i < num_planes; ++i) { int pos, size; uint raster; if (!penum->wanted[i]) continue; /* skip unwanted planes */ pos = penum->planes[i].pos; size = penum->planes[i].source.size; raster = penum->image_planes[i].raster; if (size > 0) { if (pos < raster && (pos != 0 || size < raster)) { /* Buffer a partial row. */ int copy = min(size, raster - pos); uint old_size = penum->planes[i].row.size; /* Make sure the row buffer is fully allocated. */ if (raster > old_size) { gs_memory_t *mem = gs_image_row_memory(penum); byte *old_data = penum->planes[i].row.data; byte *row = (old_data == 0 ? gs_alloc_string(mem, raster, "gs_image_next(row)") : gs_resize_string(mem, old_data, old_size, raster, "gs_image_next(row)")); if_debug5('b', "[b]plane %d row (0x%lx,%u) => (0x%lx,%u)\n", i, (ulong)old_data, old_size, (ulong)row, raster); if (row == 0) { code = gs_note_error(gs_error_VMerror); free_row_buffers(penum, i, "gs_image_next(row)"); break; } penum->planes[i].row.data = row; penum->planes[i].row.size = raster; } memcpy(penum->planes[i].row.data + pos, penum->planes[i].source.data, copy); penum->planes[i].source.data += copy; penum->planes[i].source.size = size -= copy; penum->planes[i].pos = pos += copy; used[i] += copy; } } if (h == 0) continue; /* can't transfer any data this cycle */ if (pos == raster) { /* * This plane will be transferred from the row buffer, * so we can only transfer one row. */ h = min(h, 1); penum->image_planes[i].data = penum->planes[i].row.data; } else if (pos == 0 && size >= raster) { /* We can transfer 1 or more planes from the source. */ h = min(h, size / raster); penum->image_planes[i].data = penum->planes[i].source.data; } else h = 0; /* not enough data in this plane */ } if (h == 0 || code != 0) break; /* Pass rows to the device. */ if (penum->dev == 0) { /* * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3 * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT * ****** MAY DIFFER (BY AN INTEGER FACTOR). ALSO, plane_depths[0] * ****** AND plane_widths[0] ARE NOT UPDATED. */ if (penum->y + h < penum->height) code = 0; else h = penum->height - penum->y, code = 1; } else { code = gx_image_plane_data_rows(penum->info, penum->image_planes, h, &h); if_debug2('b', "[b]used %d, code=%d\n", h, code); penum->error = code < 0; } penum->y += h; /* Update positions and sizes. */ if (h == 0) break; for (i = 0; i < num_planes; ++i) { int count; if (!penum->wanted[i]) continue; count = penum->image_planes[i].raster * h; if (penum->planes[i].pos) { /* We transferred the row from the row buffer. */ penum->planes[i].pos = 0; } else { /* We transferred the row(s) from the source. */ penum->planes[i].source.data += count; penum->planes[i].source.size -= count; used[i] += count; } } cache_planes(penum); if (code > 0) break; } /* Return the retained data pointers. */ for (i = 0; i < num_planes; ++i) plane_data[i] = penum->planes[i].source; vd_release_dc; return code; }
/* the routine sets ph->actual_frequency and ph->actual_angle. */ static int pick_cell_size(gs_screen_halftone * ph, const gs_matrix * pmat, ulong max_size, uint min_levels, bool accurate, gx_ht_cell_params_t * phcp) { const bool landscape = (pmat->xy != 0.0 || pmat->yx != 0.0); /* Account for a possibly reflected coordinate system. */ /* See gxstroke.c for the algorithm. */ const bool reflected = pmat->xy * pmat->yx > pmat->xx * pmat->yy; const int reflection = (reflected ? -1 : 1); const int rotation = (landscape ? (pmat->yx < 0 ? 90 : -90) : pmat->xx < 0 ? 180 : 0); const double f0 = ph->frequency, a0 = ph->angle; const double T = fabs((landscape ? pmat->yx / pmat->xy : pmat->xx / pmat->yy)); gs_point uv0; #define u0 uv0.x #define v0 uv0.y int rt = 1; double f = 0, a = 0; double e_best = 1000; bool better; /* * We need to find a vector in device space whose length is * 1 inch / ph->frequency and whose angle is ph->angle. * Because device pixels may not be square, we can't simply * map the length to device space and then rotate it; * instead, since we know that user space is uniform in X and Y, * we calculate the correct angle in user space before rotation. */ /* Compute trial values of u and v. */ { gs_matrix rmat; gs_make_rotation(a0 * reflection + rotation, &rmat); gs_distance_transform(72.0 / f0, 0.0, &rmat, &uv0); gs_distance_transform(u0, v0, pmat, &uv0); if_debug10('h', "[h]Requested: f=%g a=%g mat=[%g %g %g %g] max_size=%lu min_levels=%u =>\n u=%g v=%g\n", ph->frequency, ph->angle, pmat->xx, pmat->xy, pmat->yx, pmat->yy, max_size, min_levels, u0, v0); } /* Adjust u and v to reasonable values. */ if (u0 == 0 && v0 == 0) return_error(gs_error_rangecheck); while ((fabs(u0) + fabs(v0)) * rt < 4) ++rt; try_size: better = false; { double fm0 = u0 * rt; double fn0 = v0 * rt; int m0 = (int)floor(u0 * rt + 0.0001); int n0 = (int)floor(v0 * rt + 0.0001); gx_ht_cell_params_t p; p.R = p.R1 = rt; for (p.M = m0 + 1; p.M >= m0; p.M--) for (p.N = n0 + 1; p.N >= n0; p.N--) { long raster, wt, wt_size; double fr, ar, ft, at, f_diff, a_diff, f_err, a_err; p.M1 = (int)floor(p.M / T + 0.5); p.N1 = (int)floor(p.N * T + 0.5); gx_compute_cell_values(&p); if_debug3('h', "[h]trying m=%d, n=%d, r=%d\n", p.M, p.N, rt); wt = p.W; if (wt >= max_short) continue; /* Check the strip size, not the full tile size, */ /* against max_size. */ raster = bitmap_raster(wt); if (raster > max_size / p.D || raster > max_long / wt) continue; wt_size = raster * wt; /* Compute the corresponding values of F and A. */ if (landscape) ar = atan2(p.M * pmat->xy, p.N * pmat->yx), fr = 72.0 * (p.M == 0 ? pmat->xy / p.N * cos(ar) : pmat->yx / p.M * sin(ar)); else ar = atan2(p.N * pmat->xx, p.M * pmat->yy), fr = 72.0 * (p.M == 0 ? pmat->yy / p.N * sin(ar) : pmat->xx / p.M * cos(ar)); ft = fabs(fr) * rt; /* Normalize the angle to the requested quadrant. */ at = (ar * radians_to_degrees - rotation) * reflection; at -= floor(at / 180.0) * 180.0; at += floor(a0 / 180.0) * 180.0; f_diff = fabs(ft - f0); a_diff = fabs(at - a0); f_err = f_diff / fabs(f0); /* * We used to compute the percentage difference here: * a_err = (a0 == 0 ? a_diff : a_diff / fabs(a0)); * but using the angle difference makes more sense: */ a_err = a_diff; if_debug5('h', " ==> d=%d, wt=%ld, wt_size=%ld, f=%g, a=%g\n", p.D, wt, bitmap_raster(wt) * wt, ft, at); { /* * Compute the error in position between ideal location. * and the current integer location. */ double error = (fn0 - p.N) * (fn0 - p.N) + (fm0 - p.M) * (fm0 - p.M); /* * Adjust the error by the length of the vector. This gives * a slight bias toward larger cell sizzes. */ error /= p.N * p.N + p.M * p.M; error = sqrt(error); /* The previous calcs. gave value squared */ if (error > e_best) continue; e_best = error; } *phcp = p; f = ft, a = at; better = true; if_debug3('h', "*** best wt_size=%ld, f_diff=%g, a_diff=%g\n", wt_size, f_diff, a_diff); /* * We want a maximum relative frequency error of 1% and a * maximum angle error of 1% (of 90 degrees). */ if (f_err <= 0.01 && a_err <= 0.9 /*degrees*/) goto done; } } if (phcp->C < min_levels) { /* We don't have enough levels yet. Keep going. */ ++rt; goto try_size; } if (better) { /* If we want accurate screens, continue till we fail. */ if (accurate) { ++rt; goto try_size; } } else { /* * We couldn't find an acceptable M and N. If R > 1, * take what we've got; if R = 1, give up. */ if (rt == 1) return_error(gs_error_rangecheck); } /* Deliver the results. */ done: if_debug5('h', "[h]Chosen: f=%g a=%g M=%d N=%d R=%d\n", f, a, phcp->M, phcp->N, phcp->R); ph->actual_frequency = f; ph->actual_angle = a; return 0; #undef u0 #undef v0 }
/* TODO: consider using source.position and source.count (and possibly also phase) */ static int read_mode10_bitmap_data(byte ** pdata, px_args_t * par, px_state_t * pxs, bool mode9031) { px_vendor_state_t *v_state = pxs->vendor_state; mode10_state_t *mode10_state = &v_state->mode10_state; uint avail = min(par->source.available, (v_state->tag.bytes_expected - v_state->tag.bytes_so_far)); const byte *pin = par->source.data; byte *pout; bool end_of_row = false; uint32_t pixel; int i; update_pout(pout); if ((v_state->state == vu_body) && v_state->rowwritten == v_state->BlockHeight) { int code = pl_end_image(pxs->pgs, v_state->info, true); if (code < 0) return code; v_state->state = vu_blank; v_state->rowwritten = 0; return 0; } /* initialize at begin of image */ if (v_state->state == vu_tagged) { int code = vu_begin_image(pxs); if (code < 0) return code; mode10_state->state = next_is_cmd; mode10_state->cursor = 0; v_state->rowwritten = 0; v_state->state = vu_body; } /* one byte at a time until end of input or end of row */ while ((avail || mode10_state->state == process_rle) /* process_rle does not consume */ &&(!end_of_row)) { switch (mode10_state->state) { case next_is_cmd:{ mode10_state->cmd = *pin++; --avail; if_debug4('w', "command:%02X row written:%d cursor:%d cached=%08X\n", mode10_state->cmd, v_state->rowwritten, mode10_state->cursor, mode10_state->cached_pixel); mode10_state->offset = (mode10_state->cmd >> 3) & 0x03; mode10_state->count = mode10_state->cmd & 0x07; mode10_state->cursor += mode10_state->offset; /* may be partial */ if ((mode10_state->offset < 3) && (mode10_state->count < 7) && (!srcNEW(mode10_state->cmd)) ) { /* completed command */ if (mode10_state->cmd & eRLE) { mode10_state->state = process_rle; } else { /* literal, non-new */ update_pout(pout); pixel = get_pixel(pout, &mode10_state->cached_pixel, mode10_state->cmd, v_state->color_space); copy_pixel(pout, pixel); mode10_state->cursor += 1; if (mode10_state->count > 0) { mode10_state->count--; mode10_state->state = next_is_pixel; } else mode10_state->state = next_is_cmd; } } else if (mode10_state->offset == 3) mode10_state->state = partial_offset; else if (srcNEW(mode10_state->cmd)) { if ((mode10_state->cmd & eRLE) && (mode10_state->cursor >= v_state->SourceWidth)) { /* special case */ if_debug0('w', "special\n"); mode10_state->cursor = 0; end_of_row = 1; mode10_state->state = next_is_cmd; } else mode10_state->state = next_is_pixel; } else if (mode10_state->count == 7) mode10_state->state = partial_count; else mode10_state->state = next_is_cmd; /* does not happen */ break; } case partial_offset:{ uint offset = *pin++; avail--; mode10_state->offset += offset; mode10_state->cursor += offset; if (offset == 0xff) mode10_state->state = partial_offset; else { /* completed offset */ if_debug5('w', "%02X row=%d offset=%d cursor=%d/%d\n", mode10_state->cmd, v_state->rowwritten, mode10_state->offset, mode10_state->cursor, v_state->SourceWidth); if (srcNEW(mode10_state->cmd)) { if ((mode10_state->cmd & eRLE) && (mode10_state->cursor >= v_state->SourceWidth)) { /* special case */ if_debug0('w', "special\n"); mode10_state->cursor = 0; end_of_row = 1; mode10_state->state = next_is_cmd; } else mode10_state->state = next_is_pixel; } else if (mode10_state->count == 7) { mode10_state->state = partial_count; } else { /* not new pixels, counts under 7, so we need to process there */ if (mode10_state->cmd & eRLE) { mode10_state->state = process_rle; } else { /* literal non-new */ update_pout(pout); pixel = get_pixel(pout, &mode10_state->cached_pixel, mode10_state->cmd, v_state->color_space); copy_pixel(pout, pixel); mode10_state->cursor += 1; if (mode10_state->count > 0) { mode10_state->count--; mode10_state->state = next_is_pixel; } else mode10_state->state = next_is_cmd; } } } break; } case partial_count:{ uint count = *pin++; avail--; mode10_state->count += count; if (count == 0xff) mode10_state->state = partial_count; else { /* finished count - partial count only happens on RLE */ if_debug1('w', "count=%d\n", mode10_state->count); mode10_state->state = process_rle; } break; } case next_is_pixel:{ if (!mode9031 && (avail < 3)) { /* get to outer loop to get more data */ avail = 0; break; } if_debug3('w', "pixel:%02X%02X%02X\n", pin[0], pin[1], pin[2]); if (v_state->color_space == eGraySub) { /* bug in recent hpijs */ mode10_state->cached_pixel = (pin[0] << 16 | pin[0] << 8 | pin[0]) ^ 0x00ffffff; } else if (mode9031) { mode10_state->cached_pixel = (pin[0] << 16 | pin[0] << 8 | pin[0]); } else mode10_state->cached_pixel = (pin[0] << 16 | pin[1] << 8 | pin[2]); update_pout(pout); update_advance_pixel(pout, pin, mode9031); if (mode9031) { pin += 1; avail -= 1; } else { pin += 3; avail -= 3; } mode10_state->cursor++; if ((mode10_state->cmd & eRLE) && (mode10_state->count == 7)) mode10_state->state = partial_count; else if (mode10_state->cmd & eRLE) { mode10_state->state = process_rle; } else if (mode10_state->count > 0) { /* literal */ mode10_state->count--; mode10_state->state = next_is_pixel; } else mode10_state->state = next_is_cmd; break; } case process_rle:{ update_pout(pout); pixel = get_pixel(pout, &mode10_state->cached_pixel, mode10_state->cmd, v_state->color_space); mode10_state->cursor += mode10_state->count + 2; i = mode10_state->count + 2; if (srcNEW(mode10_state->cmd)) { i--; /* already moved cursor in the case of new pixel */ mode10_state->cursor--; } while (i > 0) { copy_pixel(pout, pixel); i--; } mode10_state->state = next_is_cmd; break; } } /* end switch */ /* conditional on state may not be necessary */ if ((mode10_state->state == next_is_cmd) && (mode10_state->cursor >= v_state->SourceWidth)) { mode10_state->cursor = 0; end_of_row = 1; } } /* end of while */ par->source.available -= pin - par->source.data; /* subtract compressed data used */ par->source.position += pin - par->source.data; par->source.data = pin; /* new compressed data position */ if (end_of_row) { v_state->rowwritten++; return 1; } return pxNeedData; /* not end of row so request more data */ }