static int do_page_load(gx_device_printer *pdev, gx_saved_page *page, clist_file_ptr *save_files) { int code; gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev; gs_c_param_list paramlist; /* fetch and put the params we saved with the page */ gs_c_param_list_write(¶mlist, pdev->memory); if ((code = gs_param_list_unserialize((gs_param_list *)¶mlist, page->paramlist)) < 0) goto out; gs_c_param_list_read(¶mlist); code = gs_putdeviceparams((gx_device *)pdev, (gs_param_list *)¶mlist); gs_c_param_list_release(¶mlist); if (code < 0) { goto out; } if (code > 0) if ((code = gs_opendevice((gx_device *)pdev)) < 0) goto out; /* If the device is now a writer, that means putparams realloced the device */ /* so we need to get back to reader mode and remove the extra clist files */ if (CLIST_IS_WRITER((gx_device_clist *)pdev)) { clist_close_writer_and_init_reader((gx_device_clist *)crdev); /* close and unlink the temp files just created */ if (crdev->page_info.cfile != NULL) crdev->page_info.io_procs->fclose(crdev->page_info.cfile, crdev->page_info.cfname, true); if (crdev->page_info.bfile != NULL) crdev->page_info.io_procs->fclose(crdev->page_info.bfile, crdev->page_info.bfname, true); crdev->page_info.cfile = crdev->page_info.bfile = NULL; } /* set up the page_info, after putdeviceparams that may have changed things */ crdev->page_info.io_procs = page->io_procs; crdev->page_info.tile_cache_size = page->tile_cache_size; crdev->page_info.bfile_end_pos = page->bfile_end_pos; crdev->page_info.band_params = page->band_params; crdev->yplane.index = -1; crdev->pages = NULL; crdev->num_pages = 1; /* single page at a time */ crdev->offset_map = NULL; crdev->render_threads = NULL; crdev->ymin = crdev->ymax = 0; /* invalidate buffer contents to force rasterizing */ /* We probably don't need to copy in the filenames, but do it in case something expects it */ strncpy(crdev->page_info.cfname, page->cfname, sizeof(crdev->page_info.cfname)); strncpy(crdev->page_info.bfname, page->bfname, sizeof(crdev->page_info.bfname)); if (save_files != NULL) { crdev->page_info.cfile = save_files[0]; crdev->page_info.bfile = save_files[1]; } out: return code; }
static int clist_process_page_mt(gx_device *dev, gx_process_page_options_t *options) { gx_device_printer *pdev = (gx_device_printer *)dev; gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_clist_reader *crdev = &cldev->reader; int band_height = crdev->page_info.band_params.BandHeight; int band; int num_bands = (dev->height + band_height-1)/band_height; int code; int reverse = !!(options->options & GX_PROCPAGE_BOTTOM_UP); /* This page might not want multiple threads */ /* Also we don't support plane extraction using multiple threads */ if (pdev->num_render_threads_requested < 1) return clist_process_page(dev, options); if ((code = clist_close_writer_and_init_reader(cldev)) < 0) return code; /* can't recover from this */ /* Haven't done any rendering yet, try to set up the threads */ if (clist_setup_render_threads(dev, reverse ? dev->height-1 : 0, options) < 0) /* problem setting up the threads, revert to single threaded */ return clist_process_page(dev, options); if (reverse) { for (band = num_bands-1; band > 0; band--) { code = clist_get_band_from_thread(dev, band, options); if (code < 0) goto free_thread_out; } } else { for (band = 0; band < num_bands; band++) { code = clist_get_band_from_thread(dev, band, options); if (code < 0) goto free_thread_out; } } /* Always free up thread stuff before exiting*/ free_thread_out: clist_teardown_render_threads(dev); return code; }
/* rendering adjacent to the first band (forward or backward) */ static int clist_get_bits_rect_mt(gx_device *dev, const gs_int_rect * prect, gs_get_bits_params_t *params, gs_int_rect **unread) { 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 *)dev; gx_device_clist_reader *crdev = &cldev->reader; gs_memory_t *mem = cdev->bandlist_memory; gs_get_bits_options_t options = params->options; int y = prect->p.y; int end_y = prect->q.y; int line_count = end_y - y; int band_height = crdev->page_info.band_params.BandHeight; int band = y / band_height; gs_int_rect band_rect; int lines_rasterized; gx_device *bdev; byte *mdata; uint raster = bitmap_raster(dev->width * dev->color_info.depth); int my; int code = 0; /* This page might not want multiple threads */ /* Also we don't support plane extraction using multiple threads */ if (pdev->num_render_threads_requested < 1 || (options & GB_SELECT_PLANES)) return clist_get_bits_rectangle(dev, prect, params, unread); if (prect->p.x < 0 || prect->q.x > dev->width || y < 0 || end_y > dev->height ) return_error(gs_error_rangecheck); if (line_count <= 0 || prect->p.x >= prect->q.x) return 0; if (crdev->ymin < 0) { if ((code = clist_close_writer_and_init_reader(cldev)) < 0) return code; if (clist_setup_render_threads(dev, y) < 0) /* problem setting up the threads, revert to single threaded */ return clist_get_bits_rectangle(dev, prect, params, unread); } else { if (crdev->render_threads == NULL) { /* If we get here with with ymin >=0, it's because we closed the threads */ /* while doing a page due to an error. Use single threaded mode. */ return clist_get_bits_rectangle(dev, prect, params, unread); } } /* If we already have the band's data, just return it */ if (y < crdev->ymin || end_y > crdev->ymax) code = clist_get_band_from_thread(dev, band); if (code < 0) goto free_thread_out; mdata = crdev->data + crdev->page_tile_cache_size; if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &bdev, cdev->target, y, NULL, mem, clist_get_band_complexity(dev,y))) < 0 || (code = crdev->buf_procs.setup_buf_device(bdev, mdata, raster, NULL, y - crdev->ymin, line_count, crdev->ymax - crdev->ymin)) < 0) goto free_thread_out; lines_rasterized = min(band_height, line_count); /* Return as much of the rectangle as falls within the rasterized lines. */ band_rect = *prect; band_rect.p.y = 0; band_rect.q.y = lines_rasterized; code = dev_proc(bdev, get_bits_rectangle) (bdev, &band_rect, params, unread); cdev->buf_procs.destroy_buf_device(bdev); if (code < 0) goto free_thread_out; /* Note that if called via 'get_bits', the line count will always be 1 */ if (lines_rasterized == line_count) { return code; } /***** TODO: Handle the below with data from the threads *****/ /* * We'll have to return the rectangle in pieces. Force GB_RETURN_COPY * rather than GB_RETURN_POINTER, and require all subsequent pieces to * use the same values as the first piece for all of the other format * options. If copying isn't allowed, or if there are any unread * rectangles, punt. */ if (!(options & GB_RETURN_COPY) || code > 0) return gx_default_get_bits_rectangle(dev, prect, params, unread); options = params->options; if (!(options & GB_RETURN_COPY)) { /* Redo the first piece with copying. */ params->options = options = (params->options & ~GB_RETURN_ALL) | GB_RETURN_COPY; lines_rasterized = 0; } { gs_get_bits_params_t band_params; uint raster = gx_device_raster(bdev, true); code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &bdev, cdev->target, y, NULL, mem, clist_get_band_complexity(dev, y)); if (code < 0) return code; band_params = *params; while ((y += lines_rasterized) < end_y) { /* Increment data pointer by lines_rasterized. */ if (band_params.data) band_params.data[0] += raster * lines_rasterized; line_count = end_y - y; code = clist_rasterize_lines(dev, y, line_count, bdev, NULL, &my); if (code < 0) break; lines_rasterized = min(code, line_count); band_rect.p.y = my; band_rect.q.y = my + lines_rasterized; code = dev_proc(bdev, get_bits_rectangle) (bdev, &band_rect, &band_params, unread); if (code < 0) break; params->options = options = band_params.options; if (lines_rasterized == line_count) break; } cdev->buf_procs.destroy_buf_device(bdev); } return code; /* Free up thread stuff */ free_thread_out: clist_teardown_render_threads(dev); return code; }
int clist_process_page(gx_device *dev, gx_process_page_options_t *options) { gx_device_clist *cldev = (gx_device_clist *)dev; gx_device_clist_reader *crdev = &cldev->reader; gx_device_clist_common *cdev = (gx_device_clist_common *)dev; int y; int line_count; int band_height = crdev->page_band_height; gs_int_rect band_rect; int lines_rasterized; gx_device *bdev; gx_render_plane_t render_plane; int my; int code; void *buffer = NULL; if (0 > (code = clist_close_writer_and_init_reader(cldev))) return code; if (options->init_buffer_fn) { code = options->init_buffer_fn(options->arg, dev, dev->memory, dev->width, band_height, &buffer); if (code < 0) return code; } render_plane.index = -1; for (y = 0; y < dev->height; y += lines_rasterized) { line_count = band_height; if (line_count > dev->height - y) line_count = dev->height - y; code = gdev_create_buf_device(cdev->buf_procs.create_buf_device, &bdev, cdev->target, y, &render_plane, dev->memory, &(crdev->color_usage_array[y/band_height])); if (code < 0) return code; code = clist_rasterize_lines(dev, y, line_count, bdev, &render_plane, &my); if (code >= 0) { lines_rasterized = min(code, line_count); /* Return as much of the rectangle as falls within the rasterized lines. */ band_rect.p.x = 0; band_rect.p.y = y; band_rect.q.x = dev->width; band_rect.q.y = y + lines_rasterized; if (options->process_fn) code = options->process_fn(options->arg, dev, bdev, &band_rect, buffer); } if (code >= 0 && options->output_fn) code = options->output_fn(options->arg, dev, buffer); cdev->buf_procs.destroy_buf_device(bdev); if (code < 0) break; } if (options->free_buffer_fn) { options->free_buffer_fn(options->arg, dev, dev->memory, buffer); } return code; }
/* * Print selected pages from the list to on the selected device. The * saved_pages_list is NOT modified, allowing for reprint / recovery * print. Each saved_page is printed on a separate page (unlike the * gdev_prn_render_pages above which prints several saved_pages on * a single "master" page, performing imposition). * * This is primarily intended to allow printing in non-standard order * (reverse, odd, even) or producing collated copies for a job. * * On success return the number of bytes consumed or error code < 0. * The printed_count will contain the number of pages printed. * * ------------------------------------------------------------------- * * The param string may begin with whitespace. The string is parsed * and the selected pages are printed. There may be any number of ranges * and or keywords separated by whitespace and/or comma ','. * * NB: The pdev printer device's PageCount is updated to reflect the * total number of pages produced (per the spec for this parameter) * since we may be producing multiple collated copies. * Also the list PageCount is updated after printing since * there may be a subsequent 'print' action. * keywords: * copies # Set the number of copies for subsequent printing actions * "copies 1" resets to a single copy * normal All pages are printed in normal order * reverse All pages are printed in reverse order * The following two options may be useful for duplexing. * odd All odd pages are printed, e.g. 1, 3, 5, ... * even All even pages are printed, e.g. 2, 4, 6, ... * NB: an extra blank page will be printed if the list * has an odd number of pages. * even0pad All even pages, but no extra blank page if there are * an odd number of pages on the list. * range syntax: * range range multiple ranges are separated by commas ',' * and/or whitespace. * # a specific page number is a valid range * * inclusive ranges below can have whitespace before * or after the dash '-'. * #-# a range consisting of all pages from the first * page # up to (and including) the second page #. * #-* all pages from # up through the last page * "1-*" is equivalent to "normal" * *-# all pages from the last up through # page. * "reverse" is equivalent to "*-1" */ int gx_saved_pages_list_print(gx_device_printer *pdev, gx_saved_pages_list *list, byte *param, int param_size, int *printed_count) { byte *param_scan = NULL; int param_left; int start_page = 0; /* 0 means start_page unknown */ int end_page = 0; /* < 0 means waiting for the end of a # - # range */ /* i.e, a '-' was scanned. 0 means unknown */ int tmp_num; /* during token scanning loop */ int code = 0, endcode = 0; byte *token; int copy, token_size; gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev; /* the following are used so we can go back to the original state */ bool save_bg_print = false; /* arbitrary, silence warning */ bool save_bandfile_open_close = false; /* arbitrary, silence warning */ gx_saved_page saved_page; clist_file_ptr saved_files[2]; /* save the current (empty) page while we print */ if ((code = do_page_save(pdev, &saved_page, saved_files)) < 0) { emprintf(pdev->memory, "gx_saved_pages_list_print: Error getting device params\n"); goto out; } /* save_page leaves the clist in writer mode, so prepare for reading clist */ /* files. When we are done with printing, we'll go back to write mode. */ if ((code = clist_close_writer_and_init_reader((gx_device_clist *)pdev)) < 0) goto out; /* While printing, disable the saved_pages mode and bg_print */ pdev->saved_pages_list = NULL; save_bg_print = pdev->bg_print_requested; /* Inhibits modifying the clist at end of output_page */ save_bandfile_open_close = crdev->do_not_open_or_close_bandfiles; crdev->do_not_open_or_close_bandfiles = true; pdev->PageCount = list->PageCount; /* adjust to value last printed */ /* loop producing the number of copies */ /* Note: list->collated_copies may change if 'copies' param follows the 'print' */ for (copy = 1; copy <= list->collated_copies; copy++) { int page_skip = 0; bool do_blank_page_pad; int page; /* Set to start of 'print' params to do collated copies */ param_scan = param; param_left = param_size; while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) { saved_pages_key_enum key; page = 0; do_blank_page_pad = false; /* only set for EVEN */ key = param_find_key(token, token_size); switch (key) { case PARAM_DASH: if (start_page == 0) { emprintf(pdev->memory, "gx_saved_pages_list_print: '-' unexpected\n"); code = gs_error_typecheck; goto out; } end_page = -1; /* the next number will end a range */ break; case PARAM_STAR: page = list->count; /* last page */ case PARAM_NUMBER: if (page == 0) { if (sscanf((const char *)token, "%d", &page) != 1) { emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token); code = gs_error_typecheck; goto out; } } if (start_page == 0) { start_page = page; /* first number seen */ } else { /* a second number was seen after the start_page was set */ if (end_page < 0) { end_page = page; /* end of a '# - #' range */ page_skip = (end_page >= start_page) ? 1 : -1; } else { /* 'page' was NOT part of a range after printing 'page' will start a new range */ end_page = start_page; /* single page */ page_skip = 1; } } break; case PARAM_COPIES: /* copies requires a number next */ /* Move to past 'copies' token */ param_left -= token - param_scan + token_size; param_scan = token + token_size; if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL || param_find_key(token, token_size) != PARAM_NUMBER) { emprintf(pdev->memory, "gx_saved_pages_list_print: copies not followed by number.\n"); code = gs_error_typecheck; goto out; } if (sscanf((const char *)token, "%d", &tmp_num) != 1) { emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token); code = gs_error_typecheck; goto out; } list->collated_copies = tmp_num; /* save it for our loop */ break; case PARAM_NORMAL: /* sets both start and end */ start_page = 1; end_page = list->count; page_skip = 1; break ; case PARAM_REVERSE: /* sets both start and end */ start_page = list->count; end_page = 1; page_skip = -1; break; case PARAM_EVEN: /* sets both start and end */ do_blank_page_pad = (list->count & 1) != 0; /* pad if odd */ case PARAM_EVEN0PAD: /* sets both start and end */ start_page = 2; end_page = list->count; page_skip = 2; break ; case PARAM_ODD: /* sets both start and end */ start_page = 1; end_page = list->count; page_skip = 2; break ; case PARAM_UNKNOWN: case PARAM_BEGIN: case PARAM_END: case PARAM_FLUSH: case PARAM_PRINT: token_size = 0; /* non-print range token seen */ } if (end_page > 0) { /* Here we have a range to print since start and end are known */ int curr_page = start_page; gx_saved_pages_list_element *curr_elem = NULL; /* get the start_page saved_page */ if (start_page <= list->count) { for (curr_elem = list->head; curr_elem->sequence_number != start_page; curr_elem = curr_elem->next) { if (curr_elem->next == NULL) { emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", start_page); code = gs_error_rangecheck;; goto out; } } } for ( ; curr_elem != NULL; ) { /* print the saved page from the current curr_elem */ if ((code = gx_output_saved_page(pdev, curr_elem->page)) < 0) goto out; curr_page += page_skip; if (page_skip >= 0) { if (curr_page > end_page) break; curr_elem = curr_elem->next; if (page_skip > 1) curr_elem = curr_elem->next; } else { /* reverse print order */ if (curr_page < end_page) break; curr_elem = curr_elem->prev; /* Below is not needed since we never print reverse even/odd */ if (page_skip < -1) curr_elem = curr_elem->prev; } if (curr_elem == NULL) { emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", curr_page); code = gs_error_rangecheck;; goto out; } } /* If we were printing EVEN, we may need to spit out a blank 'pad' page */ if (do_blank_page_pad) { /* print the empty page we had upon entry */ /* FIXME: Note that the page size may not match the last odd page */ if ((code = gx_output_saved_page(pdev, &saved_page)) < 0) goto out; } /* After printing, reset to handle next page range */ start_page = (start_page == end_page) ? page : 0; /* if single page, set start_page */ /* from the number scanned above */ end_page = 0; } if (token_size == 0) break; /* finished with print ranges */ /* Move to next token */ param_left -= token - param_scan + token_size; param_scan = token + token_size; } } out: /* restore the device parameters saved upon entry */ *printed_count = pdev->PageCount - list->PageCount; list->PageCount = pdev->PageCount; /* retain for subsequent print action */ pdev->saved_pages_list = list; pdev->bg_print_requested = save_bg_print; crdev->do_not_open_or_close_bandfiles = save_bandfile_open_close; /* load must be after we've set saved_pages_list which forces clist mode. */ do_page_load(pdev, &saved_page, saved_files); /* Finally, do the finish page which will reset the clist to empty and write mode */ endcode = clist_finish_page((gx_device *)pdev, true); return code < 0 ? code : endcode < 0 ? endcode : param_scan - param; }