/* Define the default implementation of ImageType 3 processing. */ static IMAGE3_MAKE_MID_PROC(make_mid_default); /* check prototype */ static int make_mid_default(gx_device **pmidev, gx_device *dev, int width, int height, gs_memory_t *mem) { gx_device_memory *midev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory, "make_mid_default"); int code; if (midev == 0) return_error(gs_error_VMerror); gs_make_mem_mono_device(midev, mem, NULL); midev->bitmap_memory = mem; midev->width = width; midev->height = height; check_device_separable((gx_device *)midev); gx_device_fill_in_procs((gx_device *)midev); code = dev_proc(midev, open_device)((gx_device *)midev); if (code < 0) { gs_free_object(mem, midev, "make_mid_default"); return code; } midev->is_open = true; dev_proc(midev, fill_rectangle) ((gx_device *)midev, 0, 0, width, height, (gx_color_index)0); *pmidev = (gx_device *)midev; return 0; }
/* Initialize a bounding box device. */ void gx_device_bbox_init(gx_device_bbox * dev, gx_device * target, gs_memory_t *mem) { gx_device_init((gx_device *) dev, (const gx_device *)&gs_bbox_device, (target ? target->memory : mem), true); if (target) { gx_device_forward_fill_in_procs((gx_device_forward *) dev); set_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix); set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color); set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb); set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color); set_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color); set_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs); set_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index); set_dev_proc(dev, encode_color, gx_forward_encode_color); set_dev_proc(dev, decode_color, gx_forward_decode_color); set_dev_proc(dev, dev_spec_op, gx_forward_dev_spec_op); set_dev_proc(dev, fill_rectangle_hl_color, gx_forward_fill_rectangle_hl_color); set_dev_proc(dev, include_color_space, gx_forward_include_color_space); set_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors); set_dev_proc(dev, get_page_device, gx_forward_get_page_device); set_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params); gx_device_set_target((gx_device_forward *)dev, target); } else { gx_device_fill_in_procs((gx_device *)dev); gx_device_forward_fill_in_procs((gx_device_forward *) dev); } dev->box_procs = box_procs_default; dev->box_proc_data = dev; bbox_copy_params(dev, false); dev->free_standing = false; /* being used as a component */ }
/* Set up a clipping path and device for insideness testing. */ static int in_path(os_ptr oppath, i_ctx_t *i_ctx_p, gx_device * phdev) { int code = gs_gsave(igs); int npop; double uxy[2]; if (code < 0) return code; code = num_params(oppath, 2, uxy); if (code >= 0) { /* Aperture is a single pixel. */ gs_point dxy; gs_fixed_rect fr; gs_transform(igs, uxy[0], uxy[1], &dxy); fr.p.x = fixed_floor(float2fixed(dxy.x)); fr.p.y = fixed_floor(float2fixed(dxy.y)); fr.q.x = fr.p.x + fixed_1; fr.q.y = fr.p.y + fixed_1; code = gx_clip_to_rectangle(igs, &fr); npop = 2; } else if (code == e_stackunderflow) { /* If 0 elements, definitely a stackunderflow; otherwise, */ /* only 1 number, also a stackunderflow. */ npop = code; } else { /* Aperture is a user path. */ /* We have to set the clipping path without disturbing */ /* the current path. */ gx_path *ipath = igs->path; gx_path save; gx_path_init_local(&save, imemory); gx_path_assign_preserve(&save, ipath); gs_newpath(igs); code = upath_append(oppath, i_ctx_p, false); if (code >= 0) code = gx_clip_to_path(igs); gx_path_assign_free(igs->path, &save); npop = 1; } if (code < 0) { gs_grestore(igs); return code; } /* Install the hit detection device. */ gx_set_device_color_1(igs); gx_device_init((gx_device *) phdev, (const gx_device *)&gs_hit_device, NULL, true); phdev->width = phdev->height = max_int; gx_device_fill_in_procs(phdev); gx_set_device_only(igs, phdev); return npop; }
static int txtwrite_open_device(gx_device * dev) { int code; gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) dev; gx_device_fill_in_procs(dev); if (tdev->fname[0] == 0) return_error(gs_error_undefinedfilename); code = gx_device_open_output_file(dev, tdev->fname, true, false, &tdev->file); /* binary, sequential */ if (code < 0) return code; return 0; }
/* Initialize a RasterOp source device. */ void gx_make_rop_texture_device(gx_device_rop_texture * dev, gx_device * target, gs_logical_operation_t log_op, const gx_device_color * texture) { gx_device_init((gx_device *) dev, (const gx_device *)&gs_rop_texture_device, NULL, true); gx_device_set_target((gx_device_forward *)dev, target); /* Drawing operations are defaulted, non-drawing are forwarded. */ check_device_separable((gx_device *) dev); gx_device_fill_in_procs((gx_device *) dev); gx_device_copy_params((gx_device *)dev, target); dev->log_op = log_op; dev->texture = *texture; }
/* * Create an imdi memory device for page or band buffering, * possibly preceded by a plane extraction device. */ int wtsimdi_create_buf_device(gx_device **pbdev, gx_device *target, const gx_render_plane_t *render_plane, gs_memory_t *mem, bool for_band) { int plane_index = (render_plane ? render_plane->index : -1); int depth; const gx_device_memory *mdproto; gx_device_memory *mdev; if (plane_index >= 0) depth = render_plane->depth; else depth = target->color_info.depth; mdproto = gdev_mem_device_for_bits(depth); if (mdproto == 0) return_error(gs_error_rangecheck); if (mem) { mdev = gs_alloc_struct(mem, gx_device_memory, &st_device_memory, "create_buf_device"); if (mdev == 0) return_error(gs_error_VMerror); } else { mdev = (gx_device_memory *)*pbdev; } if (target == (gx_device *)mdev) { /* The following is a special hack for setting up printer devices. */ assign_dev_procs(mdev, mdproto); check_device_separable((gx_device *)mdev); gx_device_fill_in_procs((gx_device *)mdev); } else gs_make_mem_device(mdev, mdproto, mem, (for_band ? 1 : 0), (target == (gx_device *)mdev ? NULL : target)); mdev->width = target->width; /* * The matrix in the memory device is irrelevant, * because all we do with the device is call the device-level * output procedures, but we may as well set it to * something halfway reasonable. */ gs_deviceinitialmatrix(target, &mdev->initial_matrix); /****** QUESTIONABLE, BUT BETTER THAN OMITTING ******/ mdev->color_info = target->color_info; *pbdev = (gx_device *)mdev; return 0; }
/* 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; gx_device *protodev; gs_c_param_list paramlist; int i, code, band; int band_count = cdev->nbands; char fmode[4]; 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) { eprintf(" 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; eprintf("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) { eprintf("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) { eprintf1("Error getting device params, code=%d. Rendering threads not started.\n", code); return code; } /* 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), mem )) < 0) { eprintf1("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 ((code = gs_putdeviceparams(ndev, (gs_param_list *)¶mlist)) < 0) break; ncdev->page_uses_transparency = cdev->page_uses_transparency; /* 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; 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; /* 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); 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); } eprintf1("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; }
int main(int argc, const char *argv[]) { char achar = '0'; gs_memory_t *mem; gs_state *pgs; const gx_device *const *list; gx_device *dev; gx_device_bbox *bbdev; int code; gp_init(); mem = gs_malloc_init(); gs_lib_init1(mem); if (argc < 2 || (achar = argv[1][0]) < '1' || achar > '0' + countof(tests) - 1 ) { lprintf1("Usage: gslib 1..%c\n", '0' + (char)countof(tests) - 1); gs_abort(mem); } gs_debug['@'] = 1; gs_debug['?'] = 1; /*gs_debug['B'] = 1; *//****** PATCH ******/ /*gs_debug['L'] = 1; *//****** PATCH ******/ /* * gs_iodev_init must be called after the rest of the inits, for * obscure reasons that really should be documented! */ gs_iodev_init(mem); /****** WRONG ******/ gs_lib_device_list(&list, NULL); gs_copydevice(&dev, list[0], mem); check_device_separable(dev); gx_device_fill_in_procs(dev); bbdev = gs_alloc_struct_immovable(mem, gx_device_bbox, &st_device_bbox, "bbox"); gx_device_bbox_init(bbdev, dev, mem); code = dev_proc(dev, get_profile)(dev, &bbdev->icc_struct); rc_increment(bbdev->icc_struct); /* Print out the device name just to test the gsparam.c API. */ { gs_c_param_list list; gs_param_string nstr; gs_c_param_list_write(&list, mem); code = gs_getdeviceparams(dev, (gs_param_list *) & list); if (code < 0) { lprintf1("getdeviceparams failed! code = %d\n", code); gs_abort(mem); } gs_c_param_list_read(&list); code = param_read_string((gs_param_list *) & list, "Name", &nstr); if (code < 0) { lprintf1("reading Name failed! code = %d\n", code); gs_abort(mem); } dputs("Device name = "); debug_print_string(nstr.data, nstr.size); dputs("\n"); gs_c_param_list_release(&list); } /* * If this is a device that takes an OutputFile, set the OutputFile * to "-" in the copy. */ { gs_c_param_list list; gs_param_string nstr; gs_c_param_list_write(&list, mem); param_string_from_string(nstr, "-"); code = param_write_string((gs_param_list *)&list, "OutputFile", &nstr); if (code < 0) { lprintf1("writing OutputFile failed! code = %d\n", code); gs_abort(mem); } gs_c_param_list_read(&list); code = gs_putdeviceparams(dev, (gs_param_list *)&list); gs_c_param_list_release(&list); if (code < 0 && code != gs_error_undefined) { lprintf1("putdeviceparams failed! code = %d\n", code); gs_abort(mem); } } dev = (gx_device *) bbdev; pgs = gs_state_alloc(mem); gs_setdevice_no_erase(pgs, dev); /* can't erase yet */ { gs_point dpi; gs_screen_halftone ht; gs_dtransform(pgs, 72.0, 72.0, &dpi); ht.frequency = min(fabs(dpi.x), fabs(dpi.y)) / 16.001; ht.angle = 0; ht.spot_function = odsf; gs_setscreen(pgs, &ht); } /* gsave and grestore (among other places) assume that */ /* there are at least 2 gstates on the graphics stack. */ /* Ensure that now. */ gs_gsave(pgs); gs_erasepage(pgs); code = (*tests[achar - '1']) (pgs, mem); gs_output_page(pgs, 1, 1); { gs_rect bbox; gx_device_bbox_bbox(bbdev, &bbox); dprintf4("Bounding box: [%g %g %g %g]\n", bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y); } if (code) dprintf1("**** Test returned code = %d.\n", code); dputs("Done. Press <enter> to exit."); fgetc(mem->gs_lib_ctx->fstdin); gs_lib_finit(0, 0, mem); return 0; #undef mem }
/* Exported for use by background printing. */ gx_device * setup_device_and_mem_for_thread(gs_memory_t *chunk_base_mem, gx_device *dev, bool bg_print, gsicc_link_cache_t **cachep) { int i, code; char fmode[4]; gs_memory_t *thread_mem; gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_printer *pdev = (gx_device_printer *)dev; gx_device_clist_common *cdev = (gx_device_clist_common *)cldev; gx_device *ndev; gx_device_clist *ncldev; gx_device_clist_common *ncdev; gx_device_printer *npdev; gx_device *protodev; gs_c_param_list paramlist; gs_devn_params *pclist_devn_params; /* 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_mem), chunk_base_mem )) < 0) { emprintf1(dev->memory, "chunk_wrap returned error code: %d\n", code); return NULL; } /* 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; /* Clone the device from the prototype device */ if (protodev == NULL || (code = gs_copydevice((gx_device **) &ndev, protodev, thread_mem)) < 0) { gs_memory_chunk_release(thread_mem); return NULL; } ncldev = (gx_device_clist *)ndev; ncdev = (gx_device_clist_common *)ndev; npdev = (gx_device_printer *)ndev; gx_device_fill_in_procs(ndev); ((gx_device_printer *)ncdev)->buffer_memory = ncdev->memory = ncdev->bandlist_memory = thread_mem; ndev->PageCount = dev->PageCount; /* copy to prevent mismatch error */ npdev->file = pdev->file; /* For background printing when doing N copies with %d */ strcpy((npdev->fname), (pdev->fname)); ndev->color_info = dev->color_info; /* copy before putdeviceparams */ ndev->pad = dev->pad; ndev->log2_align_mod = dev->log2_align_mod; ndev->is_planar = dev->is_planar; #if CMM_THREAD_SAFE ndev->icc_struct = dev->icc_struct; /* Set before put params */ rc_increment(ndev->icc_struct); #endif /* get the current device parameters to put into the cloned device */ gs_c_param_list_write(¶mlist, dev->memory); if ((code = gs_getdeviceparams(dev, (gs_param_list *)¶mlist)) < 0) { emprintf1(dev->memory, "Error getting device params, code=%d. Rendering threads not started.\n", code); goto out_cleanup; } gs_c_param_list_read(¶mlist); if ((code = gs_putdeviceparams(ndev, (gs_param_list *)¶mlist)) < 0) goto out_cleanup; gs_c_param_list_release(¶mlist); /* 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, ndev); if (code < 0) { #ifdef DEBUG /* suppress a warning on a release build */ gs_note_error(gs_error_VMerror); #endif goto out_cleanup; } } /* Also make sure supports_devn is set correctly */ ndev->icc_struct->supports_devn = cdev->icc_struct->supports_devn; ncdev->page_uses_transparency = cdev->page_uses_transparency; if_debug3m(gs_debug_flag_icc, cdev->memory, "[icc] MT clist device = 0x%p profile = 0x%p handle = 0x%p\n", ncdev, ncdev->icc_struct->device_profile[0], ncdev->icc_struct->device_profile[0]->profile_handle); /* If the device is_planar, then set the flag in the new_device and the procs */ if ((ncdev->is_planar = cdev->is_planar)) gdev_prn_set_procs_planar(ndev); /* 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) goto out_cleanup; /* close and unlink the temp files just created */ ncdev->page_info.io_procs->fclose(ncdev->page_info.cfile, ncdev->page_info.cfname, true); ncdev->page_info.io_procs->fclose(ncdev->page_info.bfile, ncdev->page_info.bfname, true); ncdev->page_info.cfile = ncdev->page_info.bfile = NULL; /* open the main thread's files for this thread */ strcpy(fmode, "r"); /* read access for threads */ strncat(fmode, gp_fmode_binary_suffix, 1); if ((code=cdev->page_info.io_procs->fopen(cdev->page_info.cfname, fmode, &ncdev->page_info.cfile, thread_mem, thread_mem, true)) < 0 || (code=cdev->page_info.io_procs->fopen(cdev->page_info.bfname, fmode, &ncdev->page_info.bfile, thread_mem, thread_mem, false)) < 0) goto out_cleanup; strcpy((ncdev->page_info.cfname), (cdev->page_info.cfname)); strcpy((ncdev->page_info.bfname), (cdev->page_info.bfname)); clist_render_init(ncldev); /* Initialize clist device for reading */ ncdev->page_info.bfile_end_pos = cdev->page_info.bfile_end_pos; /* The threads are maintained until clist_finish_page. At which point, the threads are torn down, the master clist reader device is changed to writer, and the icc_table and the icc_cache_cl freed */ #if CMM_THREAD_SAFE /* safe to share the link cache */ ncdev->icc_cache_cl = cdev->icc_cache_cl; rc_increment(cdev->icc_cache_cl, "setup_render_thread"); #else /* each thread needs its own link cache */ if (cachep != NULL) { if (*cachep == NULL) { /* We don't have one cached that we can reuse, so make one. */ if ((*cachep = gsicc_cache_new(thread_mem->thread_safe_memory)) == NULL) goto out_cleanup; } rc_increment(*cachep); ncdev->icc_cache_cl = *cachep; } else if ((ncdev->icc_cache_cl = gsicc_cache_new(thread_mem)) == NULL) goto out_cleanup; #endif if (bg_print) { gx_device_clist_reader *ncrdev = (gx_device_clist_reader *)ncdev; if (cdev->icc_table != NULL) { /* This is a background printing thread, so it cannot share the icc_table */ /* since this probably was created with a GC'ed allocator and the bg_print */ /* thread can't deal with the relocation. Free the cdev->icc_table and get */ /* a new one from the clist. */ clist_free_icc_table(cdev->icc_table, cdev->memory); cdev->icc_table = NULL; if ((code = clist_read_icctable((gx_device_clist_reader *)ncdev)) < 0) goto out_cleanup; } /* Similarly for the color_usage_array, when the foreground device switches to */ /* writer mode, the foreground's array will be freed. */ if ((code = clist_read_color_usage_array(ncrdev)) < 0) goto out_cleanup; } else { /* Use the same profile table and color usage array in each thread */ ncdev->icc_table = cdev->icc_table; /* OK for multiple rendering threads */ ((gx_device_clist_reader *)ncdev)->color_usage_array = ((gx_device_clist_reader *)cdev)->color_usage_array; } /* 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; /* success */ return ndev; out_cleanup: /* Close the file handles, but don't delete (unlink) the files */ if (ncdev->page_info.bfile != NULL) ncdev->page_info.io_procs->fclose(ncdev->page_info.bfile, ncdev->page_info.bfname, false); if (ncdev->page_info.cfile != NULL) ncdev->page_info.io_procs->fclose(ncdev->page_info.cfile, ncdev->page_info.cfname, false); ncdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */ if (ndev != NULL) { gdev_prn_free_memory(ndev); gs_free_object(thread_mem, ndev, "setup_device_and_mem_for_thread"); } gs_memory_chunk_release(thread_mem); return NULL; }
/* drawing operations. */ void gx_device_forward_fill_in_procs(register gx_device_forward * dev) { gx_device_set_procs((gx_device *) dev); /* NOT open_device */ fill_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix); fill_dev_proc(dev, sync_output, gx_forward_sync_output); fill_dev_proc(dev, output_page, gx_forward_output_page); /* NOT close_device */ fill_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color); fill_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb); /* NOT fill_rectangle */ /* NOT tile_rectangle */ /* NOT copy_mono */ /* NOT copy_color */ /* NOT draw_line (OBSOLETE) */ fill_dev_proc(dev, get_bits, gx_forward_get_bits); fill_dev_proc(dev, get_params, gx_forward_get_params); fill_dev_proc(dev, put_params, gx_forward_put_params); fill_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color); fill_dev_proc(dev, get_xfont_procs, gx_forward_get_xfont_procs); fill_dev_proc(dev, get_xfont_device, gx_forward_get_xfont_device); fill_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color); fill_dev_proc(dev, get_page_device, gx_forward_get_page_device); /* NOT get_alpha_bits (OBSOLETE) */ /* NOT copy_alpha */ fill_dev_proc(dev, get_band, gx_forward_get_band); fill_dev_proc(dev, copy_rop, gx_forward_copy_rop); fill_dev_proc(dev, fill_path, gx_forward_fill_path); fill_dev_proc(dev, stroke_path, gx_forward_stroke_path); fill_dev_proc(dev, fill_mask, gx_forward_fill_mask); fill_dev_proc(dev, fill_trapezoid, gx_forward_fill_trapezoid); fill_dev_proc(dev, fill_parallelogram, gx_forward_fill_parallelogram); fill_dev_proc(dev, fill_triangle, gx_forward_fill_triangle); fill_dev_proc(dev, draw_thin_line, gx_forward_draw_thin_line); fill_dev_proc(dev, begin_image, gx_forward_begin_image); /* NOT image_data (OBSOLETE) */ /* NOT end_image (OBSOLETE) */ /* NOT strip_tile_rectangle */ fill_dev_proc(dev, strip_copy_rop, gx_forward_strip_copy_rop); fill_dev_proc(dev, get_clipping_box, gx_forward_get_clipping_box); fill_dev_proc(dev, begin_typed_image, gx_forward_begin_typed_image); fill_dev_proc(dev, get_bits_rectangle, gx_forward_get_bits_rectangle); fill_dev_proc(dev, map_color_rgb_alpha, gx_forward_map_color_rgb_alpha); fill_dev_proc(dev, create_compositor, gx_no_create_compositor); fill_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params); fill_dev_proc(dev, text_begin, gx_forward_text_begin); fill_dev_proc(dev, get_color_mapping_procs, gx_forward_get_color_mapping_procs); fill_dev_proc(dev, get_color_comp_index, gx_forward_get_color_comp_index); fill_dev_proc(dev, encode_color, gx_forward_encode_color); fill_dev_proc(dev, decode_color, gx_forward_decode_color); fill_dev_proc(dev, pattern_manage, gx_forward_pattern_manage); fill_dev_proc(dev, fill_rectangle_hl_color, gx_forward_fill_rectangle_hl_color); fill_dev_proc(dev, include_color_space, gx_forward_include_color_space); fill_dev_proc(dev, fill_linear_color_scanline, gx_forward_fill_linear_color_scanline); fill_dev_proc(dev, fill_linear_color_trapezoid, gx_forward_fill_linear_color_trapezoid); fill_dev_proc(dev, fill_linear_color_triangle, gx_forward_fill_linear_color_triangle); fill_dev_proc(dev, update_spot_equivalent_colors, gx_forward_update_spot_equivalent_colors); fill_dev_proc(dev, ret_devn_params, gx_forward_ret_devn_params); fill_dev_proc(dev, fillpage, gx_forward_fillpage); gx_device_fill_in_procs((gx_device *) dev); }
/* Write the page. */ static int pcx2up_print_page(gx_device_printer * pdev, FILE * file) { gx_device_2up *pdev2 = (gx_device_2up *) pdev; const gx_device_printer *prdev_template = (const gx_device_printer *)&gs_pcx2up_device; if (!pdev2->have_odd_page) { /* This is the odd page, just save it. */ pdev2->have_odd_page = true; return gdev_prn_save_page(pdev, &pdev2->odd_page, 1); } else { /* This is the even page, do 2-up output. */ gx_saved_page even_page; gx_placed_page pages[2]; int x_offset = (int)(pdev->HWResolution[0] * 0.5); int code = gdev_prn_save_page(pdev, &even_page, 1); int prdev_size = prdev_template->params_size; gx_device_printer *prdev; #define rdev ((gx_device *)prdev) if (code < 0) return code; /* Create the placed page list. */ pages[0].page = &pdev2->odd_page; pages[0].offset.x = x_offset; pages[0].offset.y = 0 /*y_offset */ ; pages[1].page = &even_page; pages[1].offset.x = pdev->width + x_offset * 3; pages[1].offset.y = 0 /*y_offset */ ; /* Create and open a device for rendering. */ prdev = (gx_device_printer *) gs_alloc_bytes(pdev->memory, prdev_size, "pcx2up_print_page(device)"); if (prdev == 0) return_error(gs_error_VMerror); memcpy(prdev, prdev_template, prdev_size); check_device_separable((gx_device *)rdev); gx_device_fill_in_procs(rdev); set_dev_proc(prdev, open_device, dev_proc(&gs_pcx256_device, open_device)); prdev->printer_procs.print_page = gs_pcx256_device.printer_procs.print_page; prdev->space_params.band = pages[0].page->info.band_params; /* either one will do */ prdev->space_params.MaxBitmap = 0; prdev->space_params.BufferSpace = prdev->space_params.band.BandBufferSpace; prdev->width = prdev->space_params.band.BandWidth; prdev->OpenOutputFile = false; code = (*dev_proc(rdev, open_device)) (rdev); if (code < 0) return code; rdev->is_open = true; prdev->file = pdev->file; /* Render the pages. */ code = gdev_prn_render_pages(prdev, pages, 2); /* Clean up. */ if (pdev->file != 0) prdev->file = 0; /* don't close it */ gs_closedevice(rdev); pdev2->have_odd_page = false; return code; #undef rdev } }