int eprn_output_page(gx_device *dev, int num_copies, int flush) { eprn_Eprn *eprn = &((eprn_Device *)dev)->eprn; int rc; #ifdef EPRN_TRACE clock_t start_time = clock(); if_debug0(EPRN_TRACE_CHAR, "! eprn_output_page()...\n"); #endif /* Initialize eprn_get_planes() data */ eprn->next_y = 0; if (eprn->intensity_rendering == eprn_IR_FloydSteinberg) { /* Fetch the first line and store it in 'next_scan_line'. */ if (eprn_fetch_scan_line((eprn_Device *)dev, &eprn->next_scan_line) == 0) eprn->next_y++; } /* Ship out */ rc = gdev_prn_output_page(dev, num_copies, flush); /* CUPS page accounting message. The CUPS documentation is not perfectly clear on whether one should generate this message before printing a page or after printing has been successful. The rasterto* filters generate it before sending the page, but as the scheduler uses these messages for accounting, this seems unfair. */ if (rc == 0 && eprn->CUPS_accounting) eprintf2("PAGE: %ld %d\n", dev->ShowpageCount, num_copies); /* The arguments are the number of the page, starting at 1, and the number of copies of that page. */ #ifndef EPRN_NO_PAGECOUNTFILE /* On success, record the number of pages printed */ if (rc == 0 && eprn->pagecount_file != NULL) { assert(num_copies > 0); /* because of signed/unsigned */ if (pcf_inccount(eprn->pagecount_file, num_copies) != 0) { /* pcf_inccount() has issued an error message. */ eprintf( " No further attempts will be made to access the page count file.\n"); gs_free(dev->memory->non_gc_memory, eprn->pagecount_file, strlen(eprn->pagecount_file) + 1, sizeof(char), "eprn_output_page"); eprn->pagecount_file = NULL; } } #endif /* !EPRN_NO_PAGECOUNTFILE */ /* If soft tumble has been demanded, ensure the get_initial_matrix procedure is consulted for the next page */ if (eprn->soft_tumble) eprn_forget_defaultmatrix(dev->memory->non_gc_memory); #ifdef EPRN_TRACE if_debug1(EPRN_TRACE_CHAR, "! eprn_output_page() terminates after %f s.\n", ((float)(clock() - start_time))/CLOCKS_PER_SEC); #endif return rc; }
/* * Must be called by async device driver implementation (see gdevprna.h * under "Synchronizing the Instances"). This is the rendering loop, which * requires its own thread for as long as the device is open. This proc only * returns after the device is closed, or if the open failed. NB that an * open error leaves things in a state where the writer thread will not be * able to close since it's expecting the renderer to acknowledge its * requests before the writer can close. Ergo, if this routine fails you'll * crash unless the caller fixes the problem & successfully retries this. */ int /* rets 0 ok, -ve error code if open failed */ gdev_prn_async_render_thread( gdev_prn_start_render_params * params ) { gx_device_printer *const pwdev = params->writer_device; gx_device_printer *const prdev = pwdev->async_renderer; gx_page_queue_entry_t *entry; int code; /* Open device, but don't use default if user didn't override */ if (prdev->printer_procs.open_render_device == gx_default_open_render_device) code = gdev_prn_async_render_open(prdev); else code = (*prdev->printer_procs.open_render_device) (prdev); reinit_printer_into_renderer(prdev); /* The cmd list logic assumes reader's & writer's tile caches are same size */ if (code >= 0 && ((gx_device_clist *) pwdev)->writer.page_tile_cache_size != ((gx_device_clist *) prdev)->writer.page_tile_cache_size) { gdev_prn_async_render_close_device(prdev); code = gs_note_error(gs_error_VMerror); } params->open_code = code; gx_semaphore_signal(params->open_semaphore); if (code < 0) return code; /* fake open, since not called by gs_opendevice */ prdev->is_open = true; /* Successful open */ while ((entry = gx_page_queue_start_dequeue(prdev->page_queue)) && entry->action != GX_PAGE_QUEUE_ACTION_TERMINATE) { /* Force printer open again if it mysteriously closed. */ /* This shouldn't ever happen, but... */ if (!prdev->is_open) { if (prdev->printer_procs.open_render_device == gx_default_open_render_device) code = gdev_prn_async_render_open(prdev); else code = (*prdev->printer_procs.open_render_device) (prdev); reinit_printer_into_renderer(prdev); if (code >= 0) { prdev->is_open = true; gdev_prn_output_page((gx_device *) prdev, 0, true); } } if (prdev->is_open) { /* Force retrieved entry onto render device */ ((gx_device_clist *) prdev)->common.page_info = entry->page_info; /* Set up device geometry */ if (clist_setup_params((gx_device *) prdev) >= 0) /* Go this again, since setup_params may have trashed it */ ((gx_device_clist *) prdev)->common.page_info = entry->page_info; /* Call appropriate renderer routine to deal w/buffer */ /* Ignore status, since we don't know how to deal w/errors! */ switch (entry->action) { case GX_PAGE_QUEUE_ACTION_FULL_PAGE: (*dev_proc(prdev, output_page))((gx_device *) prdev, entry->num_copies, true); break; case GX_PAGE_QUEUE_ACTION_PARTIAL_PAGE: case GX_PAGE_QUEUE_ACTION_COPY_PAGE: (*dev_proc(prdev, output_page))((gx_device *) prdev, entry->num_copies, false); break; } /* * gx_page_queue_finish_dequeue will close and free the band * list files, so we don't need to call clist_close_output_file. */ } /* Finalize dequeue & free retrieved queue entry */ gx_page_queue_finish_dequeue(entry); } /* Close device, but don't use default if user hasn't overriden. */ /* Ignore status, since returning bad status means open failed */ if (prdev->printer_procs.close_render_device == gx_default_close_render_device) gdev_prn_async_render_close_device(prdev); else (*prdev->printer_procs.close_render_device)(prdev); /* undo fake open, since not called by gs_closedevice */ prdev->is_open = false; /* Now that device is closed, acknowledge gx_page_queue_terminate */ gx_page_queue_finish_dequeue(entry); return 0; }