/* Release all memory acquired by this allocator. */ static void gs_heap_free_all(gs_memory_t * mem, uint free_mask, client_name_t cname) { gs_malloc_memory_t *const mmem = (gs_malloc_memory_t *) mem; gx_monitor_t *mon = mmem->monitor; /* * We don't perform locking during this process since the 'monitor' * is contained in this allocator, and will get freed along the way. * It is only called at exit, and there better not be any threads * accessing this allocator. */ mmem->monitor = NULL; /* delete reference to this monitor */ gx_monitor_free(mon); /* free the monitor */ if (free_mask & FREE_ALL_DATA) { gs_malloc_block_t *bp = mmem->allocated; gs_malloc_block_t *np; for (; bp != 0; bp = np) { np = bp->next; if_debug3('a', "[a]gs_heap_free_all(%s) 0x%lx(%u)\n", client_name_string(bp->cname), (ulong) (bp + 1), bp->size); gs_alloc_fill(bp + 1, gs_alloc_fill_free, bp->size); free(bp); } } if (free_mask & FREE_ALL_ALLOCATOR) free(mem); }
/* Used for when we have to mash entire transform to CIEXYZ */ int gx_psconcretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs, frac * pconc, const gs_imager_state * pis) { const gs_cie_abc *pcie = pcs->params.abc; cie_cached_vector3 vec3; int code; if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2]); code = gx_cie_check_rendering_inline(pcs, pconc, pis); if (code < 0) return code; if (code == 1) return 0; vec3.u = float2cie_cached(pc->paint.values[0]); vec3.v = float2cie_cached(pc->paint.values[1]); vec3.w = float2cie_cached(pc->paint.values[2]); if (!pis->cie_joint_caches->skipDecodeABC) cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC, "Decode/MatrixABC"); GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs); return 0; }
gx_color_index eprn_map_rgb_color_for_RGB(gx_device *device, const gx_color_value cv[]) { gx_color_value red = cv[0], green = cv[1], blue = cv[2]; static const gx_color_value half = gx_max_color_value/2; gx_color_index value = 0; const eprn_Device *dev = (eprn_Device *)device; #ifdef EPRN_TRACE if_debug3(EPRN_TRACE_CHAR, "! eprn_map_rgb_color_for_RGB() called for RGB = (%hu, %hu, %hu),\n", red, green, blue); #endif assert(dev->eprn.colour_model == eprn_DeviceRGB); if (red > half) value |= RED_BIT; if (green > half) value |= GREEN_BIT; if (blue > half) value |= BLUE_BIT; #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); #endif return value; }
/* Evaluate a 1-Input Stitching function. */ static int fn_1ItSg_evaluate(const gs_function_t * pfn_common, const float *in, float *out) { const gs_function_1ItSg_t *const pfn = (const gs_function_1ItSg_t *)pfn_common; float arg = in[0], b0, b1, e0, encoded; int k = pfn->params.k; int i; if (arg < pfn->params.Domain[0]) { arg = pfn->params.Domain[0]; i = 0; } else if (arg > pfn->params.Domain[1]) { arg = pfn->params.Domain[1]; i = k - 1; } else { for (i = 0; i < k - 1; ++i) if (arg <= pfn->params.Bounds[i]) break; } b0 = (i == 0 ? pfn->params.Domain[0] : pfn->params.Bounds[i - 1]); b1 = (i == k - 1 ? pfn->params.Domain[1] : pfn->params.Bounds[i]); e0 = pfn->params.Encode[2 * i]; if (b1 == b0) encoded = e0; else encoded = (arg - b0) * (pfn->params.Encode[2 * i + 1] - e0) / (b1 - b0) + e0; if_debug3('~', "[~]1ItSg %g in %d => %g\n", arg, i, encoded); return gs_function_evaluate(pfn->params.Functions[i], &encoded, out); }
gx_color_index eprn_map_rgb_color_for_RGB_flex(gx_device *device, const gx_color_value cv[]) { gx_color_value red = cv[0], green = cv[1], blue = cv[2]; gx_color_index value = 0; gx_color_value step; unsigned int level; const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn; #ifdef EPRN_TRACE if_debug3(EPRN_TRACE_CHAR, "! eprn_map_rgb_color_for_RGB_flex() called for RGB = (%hu, %hu, %hu),\n", red, green, blue); #endif /* See the discussion in eprn_map_cmyk_color_flex() below. */ step = gx_max_color_value/eprn->non_black_levels; /* The order has to be BGR from left to right */ level = blue/step; if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; value = level << eprn->bits_per_colorant; level = green/step; if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; value = (value | level) << eprn->bits_per_colorant; level = red/step; if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1; value = (value | level) << eprn->bits_per_colorant; #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); #endif return value; }
gx_color_index eprn_map_rgb_color_for_CMY_or_K(gx_device *device, const gx_color_value cv[]) { gx_color_value red = cv[0], green = cv[1], blue = cv[2]; static const gx_color_value half = gx_max_color_value/2; gx_color_index value = (CYAN_BIT | MAGENTA_BIT | YELLOW_BIT); const eprn_Device *dev = (eprn_Device *)device; #ifdef EPRN_TRACE if_debug3(EPRN_TRACE_CHAR, "! eprn_map_rgb_color_for_CMY_or_K() called for RGB = (%hu, %hu, %hu),\n", red, green, blue); #endif assert(dev->eprn.colour_model == eprn_DeviceGray && red == green && green == blue && (blue == 0 || blue == gx_max_color_value) || dev->eprn.colour_model == eprn_DeviceCMY || dev->eprn.colour_model == eprn_DeviceCMY_plus_K); /* Map to CMY */ if (red > half) value &= ~CYAN_BIT; if (green > half) value &= ~MAGENTA_BIT; if (blue > half) value &= ~YELLOW_BIT; /* Remap composite black to true black if available */ if (dev->eprn.colour_model != eprn_DeviceCMY && value == (CYAN_BIT | MAGENTA_BIT | YELLOW_BIT)) value = BLACK_BIT; #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, " returning 0x%lX.\n", (unsigned long)value); #endif return value; }
gx_color_index eprn_map_rgb_color_for_CMY_or_K_flex(gx_device *device, const gx_color_value cv[]) { gx_color_value red = cv[0], green = cv[1], blue = cv[2]; const eprn_Device *dev = (eprn_Device *)device; #ifdef EPRN_TRACE if_debug3(EPRN_TRACE_CHAR, "! eprn_map_rgb_color_for_CMY_or_K_flex() called for " "RGB = (%hu, %hu, %hu).\n", red, green, blue); #endif /* Treat pure grey levels differently if we have black. This implies that for CMY+K only "true" grey shades will be printed with black ink, all others will be mixed from CMY. */ gx_color_value tmpcv[4]; if (dev->eprn.colour_model != eprn_DeviceCMY && red == green && green == blue) { tmpcv[0] = 0; tmpcv[1] = 0; tmpcv[2] = 0; tmpcv[3] = gx_max_color_value - red; return eprn_map_cmyk_color_flex(device, tmpcv); } tmpcv[0] = gx_max_color_value - red; tmpcv[1] = gx_max_color_value - green; tmpcv[2] = gx_max_color_value - blue; tmpcv[3] = 0; return eprn_map_cmyk_color_flex(device, tmpcv); }
gx_color_index eprn_map_rgb_color_for_CMY_or_K_max(gx_device *device, const gx_color_value cv[]) { gx_color_value red = cv[0], green = cv[1], blue = cv[2]; const eprn_Device *dev = (eprn_Device *)device; #ifdef EPRN_TRACE if_debug3(EPRN_TRACE_CHAR, "! eprn_map_rgb_color_for_CMY_or_K_max() called for " "RGB = (%hu, %hu, %hu).\n", red, green, blue); #endif gx_color_value tmpcv[4]; if (dev->eprn.colour_model == eprn_DeviceGray) { tmpcv[0] = 0; tmpcv[1] = 0; tmpcv[2] = 0; tmpcv[3] = gx_max_color_value - red; return eprn_map_cmyk_color_max(device, tmpcv); } /* Note that the conversion from composite black to true black for CMY+K can only happen at the output pixel level, not here. */ tmpcv[0] = gx_max_color_value - red; tmpcv[1] = gx_max_color_value - green; tmpcv[2] = gx_max_color_value - blue; tmpcv[3] = 0; return eprn_map_cmyk_color_max(device, tmpcv); }
/* Evaluate an Exponential Interpolation function. */ static int fn_ElIn_evaluate(const gs_function_t * pfn_common, const float *in, float *out) { const gs_function_ElIn_t *const pfn = (const gs_function_ElIn_t *)pfn_common; double arg = in[0], raised; int i; if (arg < pfn->params.Domain[0]) arg = pfn->params.Domain[0]; else if (arg > pfn->params.Domain[1]) arg = pfn->params.Domain[1]; raised = pow(arg, pfn->params.N); for (i = 0; i < pfn->params.n; ++i) { float v0 = (pfn->params.C0 == 0 ? 0.0 : pfn->params.C0[i]); float v1 = (pfn->params.C1 == 0 ? 1.0 : pfn->params.C1[i]); double value = v0 + raised * (v1 - v0); if (pfn->params.Range) { float r0 = pfn->params.Range[2 * i], r1 = pfn->params.Range[2 * i + 1]; if (value < r0) value = r0; else if (value > r1) value = r1; } out[i] = value; if_debug3('~', "[~]ElIn %g => [%d]%g\n", arg, i, out[i]); } return 0; }
int gx_concretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs_in, frac * pconc, const gs_imager_state * pis, gx_device *dev) { gs_color_space *pcs_icc; gs_client_color scale_pc; bool islab; gs_color_space *pcs = (gs_color_space *) pcs_in; if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2]); /* If we are comming in here then we have not completed the conversion of the ABC space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { gx_cieabc_to_icc(&pcs_icc, pcs, &islab, pis->memory->stable_memory); } else { pcs_icc = pcs->icc_equivalent; } /* Rescale the input based upon the input range since profile is created to remap this range from 0 to 1 */ if (check_range(&(pcs->params.abc->RangeABC.ranges[0]), 3)) { return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev)); } /* Do the rescale from 0 to 1 */ rescale_input_color(&(pcs->params.abc->RangeABC.ranges[0]), 3, pc, &scale_pc); /* Now the icc remap */ return((pcs_icc->type->concretize_color)(&scale_pc, pcs_icc, pconc, pis, dev)); }
/* Render a CIEBasedDEF color. */ int gx_psconcretize_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs, frac * pconc, const gs_imager_state * pis) { const gs_cie_def *pcie = pcs->params.def; int i; fixed hij[3]; frac abc[3]; cie_cached_vector3 vec3; int code; if_debug3('c', "[c]concretize DEF [%g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2]); code = gx_cie_check_rendering_inline(pcs, pconc, pis); if (code < 0) return code; if (code == 1) return 0; /* * Apply DecodeDEF, including restriction to RangeHIJ and scaling to * the Table dimensions. */ for (i = 0; i < 3; ++i) { int tdim = pcie->Table.dims[i] - 1; double factor = pcie->caches_def.DecodeDEF[i].floats.params.factor; double v0 = pc->paint.values[i]; const gs_range *const rangeDEF = &pcie->RangeDEF.ranges[i]; double value = (v0 < rangeDEF->rmin ? 0.0 : factor * (v0 > rangeDEF->rmax ? rangeDEF->rmax - rangeDEF->rmin : v0 - rangeDEF->rmin )); int vi = (int)value; double vf = value - vi; double v = pcie->caches_def.DecodeDEF[i].floats.values[vi]; if (vf != 0 && vi < factor) v += vf * (pcie->caches_def.DecodeDEF[i].floats.values[vi + 1] - v); v = (v < 0 ? 0 : v > tdim ? tdim : v); hij[i] = float2fixed(v); } /* Apply Table. */ gx_color_interpolate_linear(hij, &pcie->Table, abc); /* Scale the abc[] frac values to RangeABC cie_cached result */ vec3.u = SCALE_TO_RANGE(pcie->RangeABC.ranges[0], abc[0]); vec3.v = SCALE_TO_RANGE(pcie->RangeABC.ranges[1], abc[1]); vec3.w = SCALE_TO_RANGE(pcie->RangeABC.ranges[2], abc[2]); /* Apply DecodeABC and MatrixABC. */ if (!pis->cie_joint_caches->skipDecodeABC) cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC, "Decode/MatrixABC"); GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs); return 0; }
/* (Un)mark the strings in a chunk. */ void gc_strings_set_marks(chunk_t * cp, bool mark) { if (cp->smark != 0) { if_debug3('6', "[6]clearing string marks 0x%lx[%u] to %d\n", (ulong) cp->smark, cp->smark_size, (int)mark); memset(cp->smark, 0, cp->smark_size); if (mark) gc_mark_string(cp->sbase, cp->climit - cp->sbase, true, cp); } }
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)); }
/* error callback for jbig2 decoder */ static int s_jbig2decode_error(void *error_callback_data, const char *msg, Jbig2Severity severity, int32_t seg_idx) { stream_jbig2decode_state *const state = (stream_jbig2decode_state *) error_callback_data; const char *type; char segment[22]; int code = 0; switch (severity) { case JBIG2_SEVERITY_DEBUG: type = "DEBUG"; break;; case JBIG2_SEVERITY_INFO: type = "info"; break;; case JBIG2_SEVERITY_WARNING: type = "WARNING"; break;; case JBIG2_SEVERITY_FATAL: type = "FATAL ERROR decoding image:"; /* pass the fatal error upstream if possible */ code = gs_error_ioerror; if (state != NULL) state->error = code; break;; default: type = "unknown message:"; break;; } if (seg_idx == -1) segment[0] = '\0'; else gs_sprintf(segment, "(segment 0x%02x)", seg_idx); if (state) { if (severity == JBIG2_SEVERITY_FATAL) { dmlprintf3(state->memory, "jbig2dec %s %s %s\n", type, msg, segment); } else { if_debug3m('w', state->memory, "[w] jbig2dec %s %s %s\n", type, msg, segment); } } else { /* FIXME error_callback_data should be updated so that jbig2_ctx_new is not called with a NULL argument (see jbig2.h) and we never reach here with a NULL state */ if (severity == JBIG2_SEVERITY_FATAL) { dlprintf3("jbig2dec %s %s %s\n", type, msg, segment); } else { if_debug3('w', "[w] jbig2dec %s %s %s\n", type, msg, segment); } } return code; }
/* Free the row buffers when cleaning up. */ static void free_row_buffers(gs_image_enum *penum, int num_planes, client_name_t cname) { int i; for (i = num_planes - 1; i >= 0; --i) { if_debug3('b', "[b]free plane %d row (0x%lx,%u)\n", i, (ulong)penum->planes[i].row.data, penum->planes[i].row.size); gs_free_string(gs_image_row_memory(penum), penum->planes[i].row.data, penum->planes[i].row.size, cname); penum->planes[i].row.data = 0; penum->planes[i].row.size = 0; } }
gx_color_index eprn_map_rgb_color_for_RGB_max(gx_device *device, const gx_color_value cv[]) { gx_color_value red = cv[0], green = cv[1], blue = cv[2]; gx_color_index value; #ifdef EPRN_TRACE if_debug3(EPRN_TRACE_CHAR, "! eprn_map_rgb_color_for_RGB_max() called for RGB = (%hu, %hu, %hu),\n", red, green, blue); #endif value = dominant_8bits(red) << 8; value |= dominant_8bits(green) << 16; value |= dominant_8bits(blue) << 24; #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, " returning 0x%08lX.\n", (unsigned long)value); #endif return value; }
/* needs to be efficient. */ int gx_remap_CIEABC(const gs_client_color * pc, const gs_color_space * pcs_in, gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev, gs_color_select_t select) { gs_color_space *pcs_icc; gs_client_color scale_pc; bool islab; int i,code; gs_color_space *pcs = (gs_color_space *) pcs_in; if_debug3('c', "[c]remap CIEABC [%g %g %g]\n", pc->paint.values[0], pc->paint.values[1], pc->paint.values[2]); /* If we are comming in here then we have not completed the conversion of the ABC space to an ICC type. We will finish that process now. */ if (pcs->icc_equivalent == NULL) { gx_cieabc_to_icc(&pcs_icc, pcs, &islab, pis->memory->stable_memory); } else { pcs_icc = pcs->icc_equivalent; } /* Rescale the input based upon the input range since profile is created to remap this range from 0 to 1 */ if (check_range(&(pcs->params.abc->RangeABC.ranges[0]), 3)) { return((pcs_icc->type->remap_color)(pc,pcs_icc,pdc,pis,dev,select)); } /* Do the rescale from 0 to 1 */ rescale_input_color(&(pcs->params.abc->RangeABC.ranges[0]), 3, pc, &scale_pc); /* Now the icc remap */ code = (pcs_icc->type->remap_color)(&scale_pc,pcs_icc,pdc,pis,dev,select); /* Save unscaled data for high level device (e.g. pdfwrite) */ for (i = 0; i < 3; i++) pdc->ccolor.paint.values[i] = pc->paint.values[i]; pdc->ccolor_valid = true; /* Now the icc remap */ return(code); }
/* Set up and start the render threads */ static int clist_setup_render_threads(gx_device *dev, int y) { gx_device_printer *pdev = (gx_device_printer *)dev; gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_clist_common *cdev = (gx_device_clist_common *)cldev; gx_device_clist_reader *crdev = &cldev->reader; gs_memory_t *mem = cdev->bandlist_memory; gs_memory_t *chunk_base_mem = mem->thread_safe_memory; gs_memory_status_t mem_status; gx_device *protodev; gs_c_param_list paramlist; int i, code, band; int band_count = cdev->nbands; char fmode[4]; gs_devn_params *pclist_devn_params; crdev->num_render_threads = pdev->num_render_threads_requested; if(gs_debug[':'] != 0) dprintf1("%% %d rendering threads requested.\n", pdev->num_render_threads_requested); if (crdev->num_render_threads > band_count) crdev->num_render_threads = band_count; /* don't bother starting more threads than bands */ /* Allocate and initialize an array of thread control structures */ crdev->render_threads = (clist_render_thread_control_t *) gs_alloc_byte_array(mem, crdev->num_render_threads, sizeof(clist_render_thread_control_t), "clist_setup_render_threads" ); /* fallback to non-threaded if allocation fails */ if (crdev->render_threads == NULL) { emprintf(mem, " VMerror prevented threads from starting.\n"); return_error(gs_error_VMerror); } memset(crdev->render_threads, 0, crdev->num_render_threads * sizeof(clist_render_thread_control_t)); crdev->main_thread_data = cdev->data; /* save data area */ /* Based on the line number requested, decide the order of band rendering */ /* Almost all devices go in increasing line order (except the bmp* devices ) */ crdev->thread_lookahead_direction = (y < (cdev->height - 1)) ? 1 : -1; band = y / crdev->page_info.band_params.BandHeight; /* Close the files so we can open them in multiple threads */ if ((code = cdev->page_info.io_procs->fclose(cdev->page_cfile, cdev->page_cfname, false)) < 0 || (code = cdev->page_info.io_procs->fclose(cdev->page_bfile, cdev->page_bfname, false)) < 0) { gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads"); crdev->render_threads = NULL; emprintf(mem, "Closing clist files prevented threads from starting.\n"); return_error(gs_error_unknownerror); /* shouldn't happen */ } cdev->page_cfile = cdev->page_bfile = NULL; strcpy(fmode, "r"); /* read access for threads */ strncat(fmode, gp_fmode_binary_suffix, 1); /* Find the prototype for this device (needed so we can copy from it) */ for (i=0; (protodev = (gx_device *)gs_getdevice(i)) != NULL; i++) if (strcmp(protodev->dname, dev->dname) == 0) break; if (protodev == NULL) { emprintf(mem, "Could not find prototype device. Rendering threads not started.\n"); return gs_error_rangecheck; } gs_c_param_list_write(¶mlist, mem); if ((code = gs_getdeviceparams(dev, (gs_param_list *)¶mlist)) < 0) { emprintf1(mem, "Error getting device params, code=%d. Rendering threads not started.\n", code); return code; } /* If the 'mem' is not thread safe, we need to wrap it in a locking memory */ gs_memory_status(chunk_base_mem, &mem_status); if (mem_status.is_thread_safe == false) { return_error(gs_error_VMerror); } /* Loop creating the devices and semaphores for each thread, then start them */ for (i=0; (i < crdev->num_render_threads) && (band >= 0) && (band < band_count); i++, band += crdev->thread_lookahead_direction) { gx_device *ndev; gx_device_clist *ncldev; gx_device_clist_common *ncdev; clist_render_thread_control_t *thread = &(crdev->render_threads[i]); /* Every thread will have a 'chunk allocator' to reduce the interaction * with the 'base' allocator which has 'mutex' (locking) protection. * This improves performance of the threads. */ if ((code = gs_memory_chunk_wrap(&(thread->memory), chunk_base_mem )) < 0) { emprintf1(mem, "chunk_wrap returned error code: %d\n", code); break; } thread->band = -1; /* a value that won't match any valid band */ if ((code = gs_copydevice((gx_device **) &ndev, protodev, thread->memory)) < 0) { code = 0; /* even though we failed, no cleanup needed */ break; } ncldev = (gx_device_clist *)ndev; ncdev = (gx_device_clist_common *)ndev; gx_device_fill_in_procs(ndev); ((gx_device_printer *)ncdev)->buffer_memory = ncdev->memory = ncdev->bandlist_memory = thread->memory; gs_c_param_list_read(¶mlist); ndev->PageCount = dev->PageCount; /* copy to prevent mismatch error */ #if CMM_THREAD_SAFE ndev->icc_struct = dev->icc_struct; /* Set before put params */ rc_increment(ndev->icc_struct); #endif if ((code = gs_putdeviceparams(ndev, (gs_param_list *)¶mlist)) < 0) break; /* In the case of a separation device, we need to make sure we get the devn params copied over */ pclist_devn_params = dev_proc(dev, ret_devn_params)(dev); if (pclist_devn_params != NULL) { code = devn_copy_params(dev, (gx_device*) ncdev); if (code < 0) return_error(gs_error_VMerror); } ncdev->page_uses_transparency = cdev->page_uses_transparency; if_debug3('{',"[{]MT clist device = 0x%x profile = 0x%x handle = 0x%x\n", ncdev, ncdev->icc_struct->device_profile[0], ncdev->icc_struct->device_profile[0]->profile_handle); /* gdev_prn_allocate_memory sets the clist for writing, creating new files. * We need to unlink those files and open the main thread's files, then * reset the clist state for reading/rendering */ if ((code = gdev_prn_allocate_memory(ndev, NULL, ndev->width, ndev->height)) < 0) break; /* Needed for case when the target has cielab profile and pdf14 device has a RGB profile stored in the profile list of the clist */ ncdev->trans_dev_icc_hash = cdev->trans_dev_icc_hash; thread->cdev = ndev; /* close and unlink the temp files just created */ cdev->page_info.io_procs->fclose(ncdev->page_cfile, ncdev->page_cfname, true); cdev->page_info.io_procs->fclose(ncdev->page_bfile, ncdev->page_bfname, true); /* open the main thread's files for this thread */ if ((code=cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &ncdev->page_cfile, thread->memory, thread->memory, true)) < 0 || (code=cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &ncdev->page_bfile, thread->memory, thread->memory, false)) < 0) break; clist_render_init(ncldev); /* Initialize clist device for reading */ ncdev->page_bfile_end_pos = cdev->page_bfile_end_pos; /* Use the same link cache in each thread and the same profile table. The threads are maintained until clist_finish_page. At which point, the threads are torn down and the master clist reader device is destroyed along with the icc_table and the icc_cache_cl */ #if CMM_THREAD_SAFE ncdev->icc_cache_cl = cdev->icc_cache_cl; #else ncdev->icc_cache_cl = gsicc_cache_new(crdev->memory); #endif ncdev->icc_table = cdev->icc_table; /* create the buf device for this thread, and allocate the semaphores */ if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &(thread->bdev), cdev->target, band*crdev->page_band_height, NULL, thread->memory, clist_get_band_complexity(dev,y)) < 0)) break; if ((thread->sema_this = gx_semaphore_alloc(thread->memory)) == NULL || (thread->sema_group = gx_semaphore_alloc(thread->memory)) == NULL) { code = gs_error_VMerror; break; } /* Start thread 'i' to do band */ if ((code = clist_start_render_thread(dev, i, band)) < 0) break; } gs_c_param_list_release(¶mlist); /* If the code < 0, the last thread creation failed -- clean it up */ if (code < 0) { /* the following relies on 'free' ignoring NULL pointers */ gx_semaphore_free(crdev->render_threads[i].sema_group); gx_semaphore_free(crdev->render_threads[i].sema_this); if (crdev->render_threads[i].bdev != NULL) cdev->buf_procs.destroy_buf_device(crdev->render_threads[i].bdev); if (crdev->render_threads[i].cdev != NULL) { gx_device_clist_common *thread_cdev = (gx_device_clist_common *)crdev->render_threads[i].cdev; /* Close the file handles, but don't delete (unlink) the files */ thread_cdev->page_info.io_procs->fclose(thread_cdev->page_bfile, thread_cdev->page_bfname, false); thread_cdev->page_info.io_procs->fclose(thread_cdev->page_cfile, thread_cdev->page_cfname, false); thread_cdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */ gdev_prn_free_memory((gx_device *)thread_cdev); gs_free_object(crdev->render_threads[i].memory, thread_cdev, "clist_setup_render_threads"); } if (crdev->render_threads[i].memory != NULL) gs_memory_chunk_release(crdev->render_threads[i].memory); } /* If we weren't able to create at least one thread, punt */ /* Although a single thread isn't any more efficient, the */ /* machinery still works, so that's OK. */ if (i == 0) { if (crdev->render_threads[0].memory != NULL) { gs_memory_chunk_release(crdev->render_threads[0].memory); /* free up the locking wrapper if we allocated one */ if (chunk_base_mem != mem) { gs_memory_locked_release((gs_memory_locked_t *)chunk_base_mem); gs_free_object(mem, chunk_base_mem, "clist_setup_render_threads(locked allocator)"); } } gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads"); crdev->render_threads = NULL; /* restore the file pointers */ if (cdev->page_cfile == NULL) { char fmode[4]; strcpy(fmode, "a+"); /* file already exists and we want to re-use it */ strncat(fmode, gp_fmode_binary_suffix, 1); cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &cdev->page_cfile, mem, cdev->bandlist_memory, true); cdev->page_info.io_procs->fseek(cdev->page_cfile, 0, SEEK_SET, cdev->page_cfname); cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &cdev->page_bfile, mem, cdev->bandlist_memory, false); cdev->page_info.io_procs->fseek(cdev->page_bfile, 0, SEEK_SET, cdev->page_bfname); } emprintf1(mem, "Rendering threads not started, code=%d.\n", code); return_error(code); } crdev->num_render_threads = i; crdev->curr_render_thread = 0; if(gs_debug[':'] != 0) dprintf1("%% Using %d rendering threads\n", i); return 0; }
/* untraced space, so relocate all refs, not just marked ones. */ void igc_reloc_refs(ref_packed * from, ref_packed * to, gc_state_t * gcst) { int min_trace = gcst->min_collect; ref_packed *rp = from; bool do_all = gcst->relocating_untraced; vm_spaces spaces = gcst->spaces; const gs_memory_t *cmem = space_system->stable_memory; while (rp < to) { ref *pref; #ifdef DEBUG const void *before = 0; const void *after = 0; # define DO_RELOC(var, stat)\ BEGIN before = (var); stat; after = (var); END # define SET_RELOC(var, expr)\ BEGIN before = (var); after = (var) = (expr); END #else # define DO_RELOC(var, stat) stat # define SET_RELOC(var, expr) var = expr #endif if (r_is_packed(rp)) { rp++; continue; } /* The following assignment is logically unnecessary; */ /* we do it only for convenience in debugging. */ pref = (ref *) rp; if_debug3('8', " [8]relocating %s %d ref at 0x%lx\n", (r_has_attr(pref, l_mark) ? "marked" : "unmarked"), r_btype(pref), (ulong) pref); if ((r_has_attr(pref, l_mark) || do_all) && r_space(pref) >= min_trace ) { switch (r_type(pref)) { /* Struct cases */ case t_file: DO_RELOC(pref->value.pfile, RELOC_VAR(pref->value.pfile)); break; case t_device: DO_RELOC(pref->value.pdevice, RELOC_VAR(pref->value.pdevice)); break; case t_fontID: case t_struct: case t_astruct: DO_RELOC(pref->value.pstruct, RELOC_VAR(pref->value.pstruct)); break; /* Non-trivial non-struct cases */ case t_dictionary: rputc('d'); SET_RELOC(pref->value.pdict, (dict *)igc_reloc_ref_ptr((ref_packed *)pref->value.pdict, gcst)); break; case t_array: { uint size = r_size(pref); if (size != 0) { /* value.refs might be NULL */ /* * If the array is large, we allocated it in its * own object (at least originally -- this might * be a pointer to a subarray.) In this case, * we know it is the only object in its * containing st_refs object, so we know that * the mark containing the relocation appears * just after it. */ if (size < max_size_st_refs / sizeof(ref)) { rputc('a'); SET_RELOC(pref->value.refs, (ref *) igc_reloc_ref_ptr( (ref_packed *) pref->value.refs, gcst)); } else { rputc('A'); /* * See the t_shortarray case below for why we * decrement size. */ --size; SET_RELOC(pref->value.refs, (ref *) igc_reloc_ref_ptr( (ref_packed *) (pref->value.refs + size), gcst) - size); } } } break; case t_mixedarray: if (r_size(pref) != 0) { /* value.refs might be NULL */ rputc('m'); SET_RELOC(pref->value.packed, igc_reloc_ref_ptr(pref->value.packed, gcst)); } break; case t_shortarray: { uint size = r_size(pref); /* * Since we know that igc_reloc_ref_ptr works by * scanning forward, and we know that all the * elements of this array itself are marked, we can * save some scanning time by relocating the pointer * to the end of the array rather than the * beginning. */ if (size != 0) { /* value.refs might be NULL */ rputc('s'); /* * igc_reloc_ref_ptr has to be able to determine * whether the pointer points into a space that * isn't being collected. It does this by * checking whether the referent of the pointer * is marked. For this reason, we have to pass * a pointer to the last real element of the * array, rather than just beyond it. */ --size; SET_RELOC(pref->value.packed, igc_reloc_ref_ptr(pref->value.packed + size, gcst) - size); } } break; case t_name: { void *psub = name_ref_sub_table(cmem, pref); void *rsub = RELOC_OBJ(psub); /* gcst implicit */ SET_RELOC(pref->value.pname, (name *) ((char *)rsub + ((char *)pref->value.pname - (char *)psub))); } break; case t_string: { gs_string str; str.data = pref->value.bytes; str.size = r_size(pref); DO_RELOC(str.data, RELOC_STRING_VAR(str)); pref->value.bytes = str.data; } break; case t_oparray: rputc('o'); SET_RELOC(pref->value.const_refs, (const ref *)igc_reloc_ref_ptr((const ref_packed *)pref->value.const_refs, gcst)); break; default: goto no_reloc; /* don't print trace message */ } if_debug2('8', " [8]relocated 0x%lx => 0x%lx\n", (ulong)before, (ulong)after); } no_reloc: rp += packed_per_ref; } }
/* * Width, encoded as a variable-length uint * Height, encoded ditto * ImageMatrix (if A = 1), per gs_matrix_store/fetch * Decode (if D = 1): blocks of up to 4 components * aabbccdd, where each xx is decoded as: * 00 = default, 01 = swapped default, * 10 = (0,V), 11 = (U,V) * non-defaulted components (up to 8 floats) */ int gx_pixel_image_sput(const gs_pixel_image_t *pim, stream *s, const gs_color_space **ppcs, int extra) { const gs_color_space *pcs = pim->ColorSpace; int bpc = pim->BitsPerComponent; int num_components = gs_color_space_num_components(pcs); int num_decode; uint control = extra << PI_BITS; float decode_default_1 = 1; int i; uint ignore; /* Construct the control word. */ if (!gx_image_matrix_is_default((const gs_data_image_t *)pim)) control |= PI_ImageMatrix; switch (pim->format) { case gs_image_format_chunky: case gs_image_format_component_planar: switch (bpc) { case 1: case 2: case 4: case 8: case 12: break; default: return_error(gs_error_rangecheck); } break; case gs_image_format_bit_planar: if (bpc < 1 || bpc > 8) return_error(gs_error_rangecheck); } control |= (bpc - 1) << PI_BPC_SHIFT; control |= pim->format << PI_FORMAT_SHIFT; num_decode = num_components * 2; if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) decode_default_1 = (float)pcs->params.indexed.hival; for (i = 0; i < num_decode; ++i) if (pim->Decode[i] != DECODE_DEFAULT(i, decode_default_1)) { control |= PI_Decode; break; } if (pim->Interpolate) control |= PI_Interpolate; if (pim->CombineWithColor) control |= PI_CombineWithColor; /* Write the encoding on the stream. */ if_debug3('b', "[b]put control=0x%x, Width=%d, Height=%d\n", control, pim->Width, pim->Height); sput_variable_uint(s, control); sput_variable_uint(s, (uint)pim->Width); sput_variable_uint(s, (uint)pim->Height); if (control & PI_ImageMatrix) { debug_b_print_matrix(pim); sput_matrix(s, &pim->ImageMatrix); } if (control & PI_Decode) { int i; uint dflags = 1; float decode[8]; int di = 0; debug_b_print_decode(pim, num_decode); for (i = 0; i < num_decode; i += 2) { float u = pim->Decode[i], v = pim->Decode[i + 1]; float dv = DECODE_DEFAULT(i + 1, decode_default_1); if (dflags >= 0x100) { sputc(s, (byte)(dflags & 0xff)); sputs(s, (const byte *)decode, di * sizeof(float), &ignore); dflags = 1; di = 0; } dflags <<= 2; if (u == 0 && v == dv) DO_NOTHING; else if (u == dv && v == 0) dflags += 1; else { if (u != 0) { dflags++; decode[di++] = u; } dflags += 2; decode[di++] = v; } } sputc(s, (byte)((dflags << (8 - num_decode)) & 0xff)); sputs(s, (const byte *)decode, di * sizeof(float), &ignore); } *ppcs = pcs; return 0; }
static void gs_heap_free_object(gs_memory_t * mem, void *ptr, client_name_t cname) { gs_malloc_memory_t *mmem = (gs_malloc_memory_t *) mem; gs_malloc_block_t *bp; gs_memory_type_ptr_t pstype; struct_proc_finalize((*finalize)); if_debug3('a', "[a-]gs_free(%s) 0x%lx(%u)\n", client_name_string(cname), (ulong) ptr, (ptr == 0 ? 0 : ((gs_malloc_block_t *) ptr)[-1].size)); if (ptr == 0) return; pstype = ((gs_malloc_block_t *) ptr)[-1].type; finalize = pstype->finalize; if (finalize != 0) { if_debug3('u', "[u]finalizing %s 0x%lx (%s)\n", struct_type_name_string(pstype), (ulong) ptr, client_name_string(cname)); (*finalize) (ptr); } if (mmem->monitor) gx_monitor_enter(mmem->monitor); /* Exclusive access */ bp = mmem->allocated; /* If 'finalize' releases a memory, this function could be called recursively and change mmem->allocated. */ if (ptr == bp + 1) { mmem->allocated = bp->next; mmem->used -= bp->size + sizeof(gs_malloc_block_t); if (mmem->allocated) mmem->allocated->prev = 0; if (mmem->monitor) gx_monitor_leave(mmem->monitor); /* Done with exclusive access */ gs_alloc_fill(bp, gs_alloc_fill_free, bp->size + sizeof(gs_malloc_block_t)); free(bp); } else { gs_malloc_block_t *np; /* * bp == 0 at this point is an error, but we'd rather have an * error message than an invalid access. */ if (bp) { for (; (np = bp->next) != 0; bp = np) { if (ptr == np + 1) { bp->next = np->next; if (np->next) np->next->prev = bp; mmem->used -= np->size + sizeof(gs_malloc_block_t); if (mmem->monitor) gx_monitor_leave(mmem->monitor); /* Done with exclusive access */ gs_alloc_fill(np, gs_alloc_fill_free, np->size + sizeof(gs_malloc_block_t)); free(np); return; } } } if (mmem->monitor) gx_monitor_leave(mmem->monitor); /* Done with exclusive access */ lprintf2("%s: free 0x%lx not found!\n", client_name_string(cname), (ulong) ptr); free((char *)((gs_malloc_block_t *) ptr - 1)); } }
/* TODO: consider using source.count (and possibly also phase) */ static int read_headless_jpeg_bitmap_data(byte ** pdata, px_args_t * par, px_state_t * pxs) { px_vendor_state_t *v_state = pxs->vendor_state; uint data_per_row = v_state->data_per_row; /* jpeg doesn't pad */ uint avail = par->source.available; uint pos_in_row = par->source.position % data_per_row; const byte *data = par->source.data; stream_DCT_state *ss = (&v_state->dct_stream_state); stream_cursor_read r; stream_cursor_write w; uint used; int code = -1; if_debug3('w', "jpeg begin pos=%d row=%d/%d\n", pos_in_row, v_state->rowwritten, v_state->BlockHeight); /* consumed all of the data */ if ((v_state->state == vu_body) && v_state->rowwritten == v_state->BlockHeight) { if (par->source.available == 2) { /* the data includes EOI; the filter may or may not consume it */ par->source.data += 2; par->source.available -= 2; } gs_jpeg_destroy((&v_state->dct_stream_state)); v_state->state = vu_blank; v_state->rowwritten = 0; code = pl_end_image(pxs->pgs, v_state->info, true); if (code < 0) return code; return 0; } if (v_state->state == vu_tagged) { jpeg_decompress_data *jddp = &(v_state->jdd); v_state->rowwritten = 0; code = vu_begin_image(pxs); if (code < 0) return code; /* use the graphics library support for DCT streams */ ss->memory = pxs->memory; ss->templat = &s_DCTD_template; s_DCTD_template.set_defaults((stream_state *) ss); ss->report_error = vu_stream_error; ss->data.decompress = jddp; /* set now for allocation */ jddp->memory = ss->jpeg_memory = pxs->memory; /* set this early for safe error exit */ jddp->scanline_buffer = NULL; if (gs_jpeg_create_decompress(ss) < 0) return_error(errorInsufficientMemory); (*s_DCTD_template.init) ((stream_state *) ss); jddp->templat = s_DCTD_template; fastforward_jpeg_stream_state(jddp, ss, pxs); v_state->state = vu_body; } r.ptr = data - 1; r.limit = r.ptr + avail; if (pos_in_row < data_per_row) { /* Read more of the current row. */ byte *data = *pdata; w.ptr = data + pos_in_row - 1; w.limit = data + data_per_row - 1; code = (*s_DCTD_template.process) ((stream_state *) ss, &r, &w, false); /* code = num scanlines processed (0=need more data, -ve=error) */ if_debug1('w', "s_DCTD_template.process returns %d\n", code); used = w.ptr + 1 - data - pos_in_row; if ((code == EOFC) && (used > 0)) code = 1; if_debug2('w', "data generated: %d/%d\n", used, data_per_row); /* pos_in_row += used; */ par->source.position += used; } used = r.ptr + 1 - data; par->source.data = r.ptr + 1; par->source.available = avail - used; if_debug2('w', "scanlines %d used %d\n", code, used); if (code == 0) return pxNeedData; if (code == EOFC) /* used = 0 is possible, and earlier than end */ return 0; if (code > 0) { v_state->rowwritten++; if_debug1('w', "row written:%d\n", v_state->rowwritten); jpeg_custom_color_fixup(v_state->row, v_state->color_space, v_state->data_per_row); return 1; } return code; }
/* * Read generic pixel image parameters. */ int gx_pixel_image_sget(gs_pixel_image_t *pim, stream *s, gs_color_space *pcs) { uint control; float decode_default_1 = 1; int num_components, num_decode; int i; int code; uint ignore; if ((code = sget_variable_uint(s, &control)) < 0 || (code = sget_variable_uint(s, (uint *)&pim->Width)) < 0 || (code = sget_variable_uint(s, (uint *)&pim->Height)) < 0 ) return code; if_debug3('b', "[b]get control=0x%x, Width=%d, Height=%d\n", control, pim->Width, pim->Height); if (control & PI_ImageMatrix) { if ((code = sget_matrix(s, &pim->ImageMatrix)) < 0) return code; debug_b_print_matrix(pim); } else gx_image_matrix_set_default((gs_data_image_t *)pim); pim->BitsPerComponent = ((control >> PI_BPC_SHIFT) & PI_BPC_MASK) + 1; pim->format = (control >> PI_FORMAT_SHIFT) & PI_FORMAT_MASK; pim->ColorSpace = pcs; num_components = gs_color_space_num_components(pcs); num_decode = num_components * 2; if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) decode_default_1 = (float)pcs->params.indexed.hival; if (control & PI_Decode) { uint dflags = 0x10000; float *dp = pim->Decode; for (i = 0; i < num_decode; i += 2, dp += 2, dflags <<= 2) { if (dflags >= 0x10000) { dflags = sgetc(s) + 0x100; if (dflags < 0x100) return_error(gs_error_ioerror); } switch (dflags & 0xc0) { case 0x00: dp[0] = 0, dp[1] = DECODE_DEFAULT(i + 1, decode_default_1); break; case 0x40: dp[0] = DECODE_DEFAULT(i + 1, decode_default_1), dp[1] = 0; break; case 0x80: dp[0] = 0; if (sgets(s, (byte *)(dp + 1), sizeof(float), &ignore) < 0) return_error(gs_error_ioerror); break; case 0xc0: if (sgets(s, (byte *)dp, sizeof(float) * 2, &ignore) < 0) return_error(gs_error_ioerror); break; } } debug_b_print_decode(pim, num_decode); } else { for (i = 0; i < num_decode; ++i) pim->Decode[i] = DECODE_DEFAULT(i, decode_default_1); } pim->Interpolate = (control & PI_Interpolate) != 0; pim->CombineWithColor = (control & PI_CombineWithColor) != 0; return control >> PI_BITS; }
irender_proc_t gs_image_class_1_simple(gx_image_enum * penum) { irender_proc_t rproc; fixed ox = dda_current(penum->dda.pixel0.x); fixed oy = dda_current(penum->dda.pixel0.y); if (penum->use_rop || penum->spp != 1 || penum->bps != 1) return 0; switch (penum->posture) { case image_portrait: { /* Use fast portrait algorithm. */ long dev_width = fixed2long_pixround(ox + penum->x_extent.x) - fixed2long_pixround(ox); if (dev_width != penum->rect.w) { /* * Add an extra align_bitmap_mod of padding so that * we can align scaled rows with the device. */ long line_size = bitmap_raster(any_abs(dev_width)) + align_bitmap_mod; if (penum->adjust != 0 || line_size > max_uint) return 0; /* Must buffer a scan line. */ penum->line_width = any_abs(dev_width); penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *)penum, false); return 0; } } if_debug2('b', "[b]render=simple, unpack=copy; rect.w=%d, dev_width=%ld\n", penum->rect.w, dev_width); rproc = image_render_simple; break; } case image_landscape: { /* Use fast landscape algorithm. */ long dev_width = fixed2long_pixround(oy + penum->x_extent.y) - fixed2long_pixround(oy); long line_size = (dev_width = any_abs(dev_width), bitmap_raster(dev_width) * 8 + ROUND_UP(dev_width, 8) * align_bitmap_mod); if ((dev_width != penum->rect.w && penum->adjust != 0) || line_size > max_uint ) return 0; /* Must buffer a group of 8N scan lines. */ penum->line_width = dev_width; penum->line_size = (uint) line_size; penum->line = gs_alloc_bytes(penum->memory, penum->line_size, "image line"); if (penum->line == 0) { gx_default_end_image(penum->dev, (gx_image_enum_common_t *) penum, false); return 0; } penum->xi_next = penum->line_xy = fixed2int_var_rounded(ox); if_debug3('b', "[b]render=landscape, unpack=copy; rect.w=%d, dev_width=%ld, line_size=%ld\n", penum->rect.w, dev_width, line_size); rproc = image_render_landscape; /* Precompute values needed for rasterizing. */ penum->dxy = float2fixed(penum->matrix.xy + fixed2float(fixed_epsilon) / 2); break; } default: return 0; } /* Precompute values needed for rasterizing. */ penum->dxx = float2fixed(penum->matrix.xx + fixed2float(fixed_epsilon) / 2); /* * We don't want to spread the samples, but we have to reset unpack_bps * to prevent the buffer pointer from being incremented by 8 bytes per * input byte. */ penum->unpack = sample_unpack_copy; penum->unpack_bps = 8; if (penum->use_mask_color) { /* * Set the masked color as 'no_color' to make it transparent * according to the mask color range and the decoding. */ penum->masked = true; if (penum->mask_color.values[0] == 1) { /* if v0 == 1, 1 is transparent since v1 must be == 1 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor0 : penum->icolor1, gx_no_color_index); } else if (penum->mask_color.values[1] == 0) { /* if v1 == 0, 0 is transparent since v0 must be == 0 to be a valid range */ set_nonclient_dev_color(penum->map[0].inverted ? penum->icolor1 : penum->icolor0, gx_no_color_index); } else { /* * The only other possible in-range value is v0 = 0, v1 = 1. * The image is completely transparent! */ rproc = image_render_skip; } penum->map[0].decoding = sd_none; } return rproc; }
/* 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 */ }
/* 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; } }
/* Set the relocation for a ref object. */ static bool refs_set_reloc(obj_header_t * hdr, uint reloc, uint size) { ref_packed *rp = (ref_packed *) (hdr + 1); ref_packed *end = (ref_packed *) ((byte *) rp + size); uint freed = 0; /* * We have to be careful to keep refs aligned properly. * For the moment, we do this by either keeping or discarding * an entire (aligned) block of align_packed_per_ref packed elements * as a unit. We know that align_packed_per_ref <= packed_per_ref, * and we also know that packed refs are always allocated in blocks * of align_packed_per_ref, so this makes things relatively easy. */ while (rp < end) { if (r_is_packed(rp)) { #if align_packed_per_ref == 1 if (r_has_pmark(rp)) { if_debug1('8', " [8]packed ref 0x%lx is marked\n", (ulong) rp); rp++; } else { #else int i; /* * Note: align_packed_per_ref is typically * 2 or 4 for 32-bit processors. */ #define all_marked (align_packed_per_ref * lp_mark) # if align_packed_per_ref == 2 # if arch_sizeof_int == arch_sizeof_short * 2 # undef all_marked # define all_marked ( (lp_mark << (sizeof(short) * 8)) + lp_mark ) # define marked (*(int *)rp & all_marked) # else # define marked ((*rp & lp_mark) + (rp[1] & lp_mark)) # endif # else # if align_packed_per_ref == 4 # define marked ((*rp & lp_mark) + (rp[1] & lp_mark) +\ (rp[2] & lp_mark) + (rp[3] & lp_mark)) # else /* * The value of marked is logically a uint, not an int: * we declare it as int only to avoid a compiler warning * message about using a non-int value in a switch statement. */ int marked = *rp & lp_mark; for (i = 1; i < align_packed_per_ref; i++) marked += rp[i] & lp_mark; # endif # endif /* * Now marked is lp_mark * the number of marked * packed refs in the aligned block, except for * a couple of special cases above. */ switch (marked) { case all_marked: if_debug2('8', " [8]packed refs 0x%lx..0x%lx are marked\n", (ulong) rp, (ulong) (rp + (align_packed_per_ref - 1))); rp += align_packed_per_ref; break; default: /* At least one packed ref in the block */ /* is marked: Keep the whole block. */ for (i = align_packed_per_ref; i--; rp++) { r_set_pmark(rp); if_debug1('8', " [8]packed ref 0x%lx is marked\n", (ulong) rp); } break; case 0: #endif if_debug2('8', " [8]%d packed ref(s) at 0x%lx are unmarked\n", align_packed_per_ref, (ulong) rp); { uint rel = reloc + freed; /* Change this to an integer so we can */ /* store the relocation here. */ *rp = pt_tag(pt_integer) + min(rel, packed_max_value); } rp += align_packed_per_ref; freed += sizeof(ref_packed) * align_packed_per_ref; } } else { /* full-size ref */ uint rel = reloc + freed; /* The following assignment is logically */ /* unnecessary; we do it only for convenience */ /* in debugging. */ ref *pref = (ref *) rp; if (!r_has_attr(pref, l_mark)) { if_debug1('8', " [8]ref 0x%lx is unmarked\n", (ulong) pref); /* Change this to a mark so we can */ /* store the relocation. */ r_set_type(pref, t_mark); r_set_size(pref, rel); freed += sizeof(ref); } else { if_debug1('8', " [8]ref 0x%lx is marked\n", (ulong) pref); /* Store the relocation here if possible. */ if (!ref_type_uses_size_or_null(r_type(pref))) { if_debug2('8', " [8]storing reloc %u at 0x%lx\n", rel, (ulong) pref); r_set_size(pref, rel); } } rp += packed_per_ref; } } if_debug3('7', " [7]at end of refs 0x%lx, size = %u, freed = %u\n", (ulong) (hdr + 1), size, freed); if (freed == size) return false; #if arch_sizeof_int > arch_sizeof_short /* * If the final relocation can't fit in the r_size field * (which can't happen if the object shares a chunk with * any other objects, so we know reloc = 0 in this case), * we have to keep the entire object unless there are no * references to any ref in it. */ if (freed <= max_ushort) return true; /* * We have to mark all surviving refs, but we also must * overwrite any non-surviving refs with something that * doesn't contain any pointers. */ rp = (ref_packed *) (hdr + 1); while (rp < end) { if (r_is_packed(rp)) { if (!r_has_pmark(rp)) *rp = pt_tag(pt_integer) | lp_mark; ++rp; } else { /* The following assignment is logically */ /* unnecessary; we do it only for convenience */ /* in debugging. */ ref *pref = (ref *) rp; if (!r_has_attr(pref, l_mark)) { r_set_type_attrs(pref, t_mark, l_mark); r_set_size(pref, reloc); } else { if (!ref_type_uses_size_or_null(r_type(pref))) r_set_size(pref, reloc); } rp += packed_per_ref; } } /* The last ref has to remain unmarked. */ r_clear_attrs((ref *) rp - 1, l_mark); #endif return true; }
/* 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 }
int eprn_set_page_layout(eprn_Device *dev) { bool no_match = true, /* Are the requested flags supported for some size? */ landscape = dev->MediaSize[0] > dev->MediaSize[1]; /* 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. */ const char *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: ""; const eprn_CustomPageDescription *best_cmatch = NULL; /* best custom page size match */ eprn_Eprn *eprn = &dev->eprn; const eprn_PageDescription *best_cdmatch = NULL, /* best custom page size match in discrete list*/ *best_dmatch = NULL, /* best discrete match */ *pd; /* loop variable */ float /* Page width and height in bp with w <= h (in a moment): */ w = dev->MediaSize[0], h = dev->MediaSize[1], /* pixmap device space margins in bp (canonical order): */ margins[4]; int quarters; ms_MediaCode desired = eprn->desired_flags; #ifdef EPRN_TRACE if_debug3(EPRN_TRACE_CHAR, "! eprn_set_page_layout(): PageSize = [%.0f %.0f], " "desired_flags = 0x%04X.\n", dev->MediaSize[0], dev->MediaSize[1], (unsigned int)desired); #endif /* Ensure w <= h */ if (w > h) { float temp; temp = w; w = h; h = temp; /* This has effectively split 'MediaSize[]' into 'w', 'h' and 'landscape'. */ } /* Initialization of primary return value */ eprn->code = ms_none; /* Put the LeadingEdge value into the desired flag pattern if it's set */ if (eprn->leading_edge_set) { if (eprn->default_orientation % 2 == 0) /* true on short edge first */ desired &= ~MS_TRANSVERSE_FLAG; else desired |= MS_TRANSVERSE_FLAG; } /* Find best match in discrete sizes */ if (eprn->media_overrides == NULL) pd = eprn->cap->sizes; else pd = eprn->media_overrides; while (pd->code != ms_none) { const ms_SizeDescription *ms = ms_find_size_from_code(pd->code); if (ms->dimen[0] > 0.0 /* ignore variable sizes */ && fabs(w - ms->dimen[0]) <= 5.0 && fabs(h - ms->dimen[1]) <= 5.0) { /* The size does match at 5 bp tolerance. This value has been chosen arbitrarily to be equal to PostScript's PageSize matching tolerance during media selection. The tolerance should really be that at which the printer in question distinguishes between sizes or smaller than that in order to at least prevent printing on unsupported sizes. */ if (best_dmatch == NULL || better_flag_match(desired, eprn->optional_flags, best_dmatch->code, pd->code)) best_dmatch = pd; if (flag_match(desired, eprn->optional_flags, pd->code)) no_match = false; } pd++; } /* Next find the best match among the custom size descriptions */ if (eprn->cap->custom != NULL) { const eprn_CustomPageDescription *cp = eprn->cap->custom; /* First check whether the size is in the supported range */ while (cp->width_max > 0.0) { if (cp->width_min <= w && w <= cp->width_max && cp->height_min <= h && h <= cp->height_max) { /* The size does match. */ if (best_cmatch == NULL || better_flag_match(desired, eprn->optional_flags, best_cmatch->code, cp->code)) best_cmatch = cp; if (eprn->media_overrides == NULL && flag_match(desired, eprn->optional_flags, cp->code)) no_match = false; } cp++; } /* If we have read a media configuration file, the flags to be matched must be sought in 'media_overrides'. */ if (best_cmatch != NULL && eprn->media_overrides != NULL) { for (pd = eprn->media_overrides; pd->code != ms_none; pd++) { if (ms_without_flags(pd->code) == ms_CustomPageSize) { if (best_cdmatch == NULL || better_flag_match(desired, eprn->optional_flags, best_cdmatch->code, pd->code)) best_cdmatch = pd; if (flag_match(desired, eprn->optional_flags, pd->code)) no_match = false; } } } } /* Now the 'best_*match' variables indicate for each of the categories of page descriptions to which extent the size is supported at all (non-NULL value) and what the best flag match in the category is. Here we now check for NULL values, i.e., size matches. */ if (best_dmatch == NULL) { /* No discrete match */ if (best_cmatch == NULL) { /* No match at all. */ eprintf3("%s" ERRPREF "This document requests a page size of %.0f x %.0f bp.\n", epref, dev->MediaSize[0], dev->MediaSize[1]); if (eprn->cap->custom == NULL) { /* The printer does not support custom page sizes */ if (eprn->media_overrides != NULL) eprintf1( "%s The media configuration file does not contain an entry for " " this size.\n", epref); else eprintf2("%s This size is not supported by the %s.\n", epref, eprn->cap->name); } else eprintf3( "%s This size is not supported as a discrete size and it exceeds " "the\n" "%s custom page size limits for the %s.\n", epref, epref, eprn->cap->name); return -1; } if (eprn->media_overrides != NULL && best_cdmatch == NULL) { eprintf6("%s" ERRPREF "This document requests a page size of %.0f x %.0f bp\n" "%s but there is no entry for this size in the " "media configuration file\n" "%s %s.\n", epref, dev->MediaSize[0], dev->MediaSize[1], epref, epref, eprn->media_file); return -1; } } /* Now we have: best_dmatch != NULL || best_cmatch != NULL && (eprn->media_overrides == NULL || best_cdmatch != NULL). */ /* Find a flag match among the size matches found so far */ { ms_MediaCode custom_code = ms_none; /* best custom page size match (either from cmatch or dcmatch) */ if (best_cmatch != NULL && (eprn->media_overrides == NULL || best_cdmatch != NULL)) custom_code = (eprn->media_overrides == NULL? best_cmatch->code: best_cdmatch->code); if (best_dmatch == NULL || best_cmatch != NULL && better_flag_match(desired, eprn->optional_flags, best_dmatch->code, custom_code)) { if (flag_match(desired, eprn->optional_flags, custom_code)) { if (eprn->media_overrides == NULL) { eprn->code = best_cmatch->code; margins[0] = best_cmatch->left; margins[1] = best_cmatch->bottom; margins[2] = best_cmatch->right; margins[3] = best_cmatch->top; } else { eprn->code = best_cdmatch->code; margins[0] = best_cdmatch->left; margins[1] = best_cdmatch->bottom; margins[2] = best_cdmatch->right; margins[3] = best_cdmatch->top; } } } else { if (flag_match(desired, eprn->optional_flags, best_dmatch->code)) { eprn->code = best_dmatch->code; margins[0] = best_dmatch->left; margins[1] = best_dmatch->bottom; margins[2] = best_dmatch->right; margins[3] = best_dmatch->top; } } } /* If we've found a match, 'code' is no longer 'ms_none'. */ if (eprn->code == ms_none) { eprn_flag_mismatch(eprn, no_match); return -1; } /* Adapt the orientation of default default user space if not prescribed */ if (!eprn->leading_edge_set) { if (eprn->code & MS_TRANSVERSE_FLAG) eprn->default_orientation = 3; /* This leads to 0 if landscape orientation is requested. */ else eprn->default_orientation = 0; } /* Now 'eprn->default_orientation % 2' describes the sheet's orientation in pixmap device space. If this does not agree with the width and height values in the device instance, we'll have to adapt them. This is only necessary if there is a significant difference between width and height. */ if (fabs(w - h) > 1 /* arbitrary */ && (eprn->default_orientation % 2 == 0) != (dev->width/dev->HWResolution[0] <= dev->height/dev->HWResolution[1])) { bool reallocate = false; #ifdef EPRN_TRACE if_debug0(EPRN_TRACE_CHAR, "! eprn_set_page_layout(): width-height change is necessary.\n"); #endif /* Free old storage if the device is open */ if (dev->is_open) { #ifdef EPRN_TRACE if_debug0(EPRN_TRACE_CHAR, "! eprn_set_page_layout(): Device is open.\n"); #endif reallocate = true; /* One could try and call the allocation/reallocation routines of the prn device directly, but they are not available in older ghostscript versions and this method is safer anyway because it relies on a documented API. */ gdev_prn_close((gx_device *)dev); /* ignore the result */ } /* Now set width and height via gx_device_set_media_size(). This function sets 'MediaSize[]', 'width', and 'height' based on the assumption that default user space has a y axis which is vertical in pixmap device space. This may be wrong and we have to fix it. Because fixing 'MediaSize[]' is simpler, gx_device_set_media_size() is called such that it gives the correct values for 'width' and 'height'. */ if (eprn->default_orientation % 2 == 0) { /* portrait orientation of the sheet in pixmap device space */ gx_device_set_media_size((gx_device *)dev, w, h); if (landscape) { dev->MediaSize[0] = h; dev->MediaSize[1] = w; } } else { /* landscape orientation in pixmap device space (transverse) */ gx_device_set_media_size((gx_device *)dev, h, w); if (!landscape) { dev->MediaSize[0] = w; dev->MediaSize[1] = h; } } /* If the device is/was open, reallocate storage */ if (reallocate) { int rc; rc = gdev_prn_open((gx_device *)dev); if (rc < 0) { eprintf2("%s" ERRPREF "Failure of gdev_prn_open(), code is %d.\n", epref, rc); return rc; } } } /* Increase the bottom margin for coloured modes except if it is exactly zero */ if (eprn->colour_model != eprn_DeviceGray && margins[1] != 0.0) margins[1] += eprn->cap->bottom_increment; /* Number of +90-degree rotations needed for default user space: */ quarters = eprn->default_orientation; if (landscape) quarters = (quarters + 1)%4; /* Store the top and left margins in the device structure for use by eprn_get_initial_matrix() and set the margins of the printable area if we may. gx_device_set_margins() (see gsdevice.c) copies the margins[] array to HWMargins[] which is presumably to be interpreted in default user space (see gs_initclip() in gspath.c), and if its second argument is true it also modifies the offset variable Margins[]. The first property means that gx_device_set_margins() can only be used if default user space and pixmap device space have the same "up" direction, and the second appropriates a parameter which is intended for the user. */ if (eprn->keep_margins) { eprn->down_shift = dev->HWMargins[3 - quarters]; eprn->right_shift = dev->HWMargins[(4 - quarters)%4]; } else { int j; eprn->down_shift = margins[3]; eprn->right_shift = margins[0]; if (quarters != 0) { /* The "canonical margin order" for ghostscript is left, bottom, right, top. Hence for, e.g., a +90-degree rotation ('quarters' is 1) of default user space with respect to pixmap device space the left margin (index 0) in default user space is actually the bottom margin (index 1) in pixmap device space, the bottom margin is the right one, etc. */ for (j = 0; j < 4; j++) dev->HWMargins[j] = margins[(j+quarters)%4]; /* 'HWMargins[]' is in bp (see gxdevcli.h) */ } else { /* Convert to inches */ for (j = 0; j < 4; j++) margins[j] /= BP_PER_IN; gx_device_set_margins((gx_device *)dev, margins, false); /* Of course, I could set HWMargins[] directly also in this case. This way is however less prone to break on possible future incompatible changes to ghostscript and it covers the most frequent case (portrait and short edge first). */ } } return 0; }
/* Process a buffer */ static int s_DCTD_process(stream_state * st, stream_cursor_read * pr, stream_cursor_write * pw, bool last) { stream_DCT_state *const ss = (stream_DCT_state *) st; jpeg_decompress_data *jddp = ss->data.decompress; struct jpeg_source_mgr *src = jddp->dinfo.src; int code; if_debug3('w', "[wdd]process avail=%u, skip=%u, last=%d\n", (uint) (pr->limit - pr->ptr), (uint) jddp->skip, last); if (jddp->skip != 0) { long avail = pr->limit - pr->ptr; if (avail < jddp->skip) { jddp->skip -= avail; pr->ptr = pr->limit; if (!last) return 0; /* need more data */ jddp->skip = 0; /* don't skip past input EOD */ } pr->ptr += jddp->skip; jddp->skip = 0; } src->next_input_byte = pr->ptr + 1; src->bytes_in_buffer = pr->limit - pr->ptr; jddp->input_eod = last; switch (ss->phase) { case 0: /* not initialized yet */ /* * Adobe implementations seem to ignore leading garbage bytes, * even though neither the standard nor Adobe's own * documentation mention this. */ while (pr->ptr < pr->limit && pr->ptr[1] != 0xff) pr->ptr++; if (pr->ptr == pr->limit) return 0; src->next_input_byte = pr->ptr + 1; src->bytes_in_buffer = pr->limit - pr->ptr; ss->phase = 1; /* falls through */ case 1: /* reading header markers */ if ((code = gs_jpeg_read_header(ss, TRUE)) < 0) return ERRC; pr->ptr = (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1); switch (code) { case JPEG_SUSPENDED: return 0; /*case JPEG_HEADER_OK: */ } /* If we have a ColorTransform parameter, and it's not * overridden by an Adobe marker in the data, set colorspace. */ if (ss->ColorTransform >= 0 && !jddp->dinfo.saw_Adobe_marker) { switch (jddp->dinfo.num_components) { case 3: jddp->dinfo.jpeg_color_space = (ss->ColorTransform ? JCS_YCbCr : JCS_RGB); /* out_color_space will default to JCS_RGB */ break; case 4: jddp->dinfo.jpeg_color_space = (ss->ColorTransform ? JCS_YCCK : JCS_CMYK); /* out_color_space will default to JCS_CMYK */ break; } } ss->phase = 2; /* falls through */ case 2: /* start_decompress */ if ((code = gs_jpeg_start_decompress(ss)) < 0) return ERRC; pr->ptr = (jddp->faked_eoi ? pr->limit : src->next_input_byte - 1); if (code == 0) return 0; ss->scan_line_size = jddp->dinfo.output_width * jddp->dinfo.output_components; if_debug4('w', "[wdd]width=%u, components=%d, scan_line_size=%u, min_out_size=%u\n", jddp->dinfo.output_width, jddp->dinfo.output_components, ss->scan_line_size, jddp->template.min_out_size);