2018-07-19 17:49:33 +02:00
|
|
|
/*
|
|
|
|
* GDSII-Converter
|
|
|
|
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
|
|
|
|
*
|
|
|
|
* This file is part of GDSII-Converter.
|
|
|
|
*
|
|
|
|
* GDSII-Converter is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* GDSII-Converter is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2019-11-17 15:52:28 +01:00
|
|
|
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
2018-07-19 17:49:33 +02:00
|
|
|
*/
|
2018-07-30 12:35:30 +02:00
|
|
|
/**
|
2019-10-25 21:16:31 +02:00
|
|
|
* @file cairo-renderer.c
|
|
|
|
* @brief Output renderer for Cairo PDF export
|
|
|
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
|
|
*/
|
2018-07-24 14:42:28 +02:00
|
|
|
|
2019-08-26 20:37:48 +02:00
|
|
|
/** @addtogroup Cairo-Renderer
|
2018-07-24 14:42:28 +02:00
|
|
|
* @{
|
|
|
|
*/
|
2018-07-19 17:49:33 +02:00
|
|
|
|
|
|
|
#include <math.h>
|
2018-07-19 18:45:37 +02:00
|
|
|
#include <stdlib.h>
|
2018-07-19 17:49:33 +02:00
|
|
|
#include <cairo.h>
|
|
|
|
#include <cairo-pdf.h>
|
2018-07-30 12:35:30 +02:00
|
|
|
#include <cairo-svg.h>
|
2019-12-12 21:22:14 +01:00
|
|
|
#include <glib/gi18n.h>
|
2018-07-19 17:49:33 +02:00
|
|
|
|
2019-06-19 19:01:40 +02:00
|
|
|
#include <gds-render/output-renderers/cairo-renderer.h>
|
2019-05-30 14:49:35 +02:00
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
2019-03-26 19:57:19 +01:00
|
|
|
|
2019-06-19 19:21:20 +02:00
|
|
|
struct _CairoRenderer {
|
|
|
|
GdsOutputRenderer parent;
|
|
|
|
gboolean svg; /**< @brief TRUE: SVG output, FALSE: PDF output */
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(CairoRenderer, cairo_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
|
|
|
|
|
2018-07-24 14:42:28 +02:00
|
|
|
/**
|
|
|
|
* @brief The cairo_layer struct
|
|
|
|
* Each rendered layer is represented by this struct.
|
|
|
|
*/
|
2018-07-19 18:45:37 +02:00
|
|
|
struct cairo_layer {
|
2018-07-30 12:35:30 +02:00
|
|
|
cairo_t *cr; /**< @brief cairo context for layer*/
|
|
|
|
cairo_surface_t *rec; /**< @brief Recording surface to hold the layer */
|
|
|
|
struct layer_info *linfo; /**< @brief Reference to layer information */
|
2018-07-19 18:45:37 +02:00
|
|
|
};
|
|
|
|
|
2018-07-24 14:42:28 +02:00
|
|
|
/**
|
|
|
|
* @brief Revert the last transformation on all layers
|
|
|
|
* @param layers Pointer to #cairo_layer structures
|
|
|
|
*/
|
2018-07-20 22:32:23 +02:00
|
|
|
static void revert_inherited_transform(struct cairo_layer *layers)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_LAYERS; i++) {
|
|
|
|
if (layers[i].cr == NULL)
|
2018-07-22 16:38:26 +02:00
|
|
|
continue;
|
2018-07-20 22:32:23 +02:00
|
|
|
cairo_restore(layers[i].cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 14:42:28 +02:00
|
|
|
/**
|
|
|
|
* @brief Applies transformation to all layers
|
|
|
|
* @param layers Array of layers
|
|
|
|
* @param origin Origin translation
|
|
|
|
* @param magnification Scaling
|
|
|
|
* @param flipping Mirror image on x-axis before rotating
|
2019-08-19 19:54:53 +02:00
|
|
|
* @param rotation Rotation in degrees
|
2018-07-24 14:42:28 +02:00
|
|
|
* @param scale Scale the image down by. Only used for sclaing origin coordinates. Not applied to layer.
|
|
|
|
*/
|
2018-07-20 22:32:23 +02:00
|
|
|
static void apply_inherited_transform_to_all_layers(struct cairo_layer *layers,
|
|
|
|
const struct gds_point *origin,
|
|
|
|
double magnification,
|
|
|
|
gboolean flipping,
|
|
|
|
double rotation,
|
|
|
|
double scale)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
cairo_t *temp_layer_cr;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_LAYERS; i++) {
|
|
|
|
temp_layer_cr = layers[i].cr;
|
|
|
|
if (temp_layer_cr == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Save the state and apply transformation */
|
|
|
|
cairo_save(temp_layer_cr);
|
|
|
|
cairo_translate(temp_layer_cr, (double)origin->x/scale, (double)origin->y/scale);
|
|
|
|
cairo_rotate(temp_layer_cr, M_PI*rotation/180.0);
|
|
|
|
cairo_scale(temp_layer_cr, magnification,
|
|
|
|
(flipping == TRUE ? -magnification : magnification));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 14:42:28 +02:00
|
|
|
/**
|
|
|
|
* @brief render_cell Render a cell with its sub-cells
|
|
|
|
* @param cell Cell to render
|
|
|
|
* @param layers Cell will be rendered into these layers
|
|
|
|
* @param scale sclae image down by this factor
|
|
|
|
*/
|
2018-07-20 22:32:23 +02:00
|
|
|
static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, double scale)
|
|
|
|
{
|
|
|
|
GList *instance_list;
|
|
|
|
struct gds_cell *temp_cell;
|
|
|
|
struct gds_cell_instance *cell_instance;
|
|
|
|
GList *gfx_list;
|
|
|
|
struct gds_graphics *gfx;
|
|
|
|
GList *vertex_list;
|
|
|
|
struct gds_point *vertex;
|
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
/* Render child cells */
|
|
|
|
for (instance_list = cell->child_cells; instance_list != NULL; instance_list = instance_list->next) {
|
|
|
|
cell_instance = (struct gds_cell_instance *)instance_list->data;
|
2019-10-25 21:16:31 +02:00
|
|
|
temp_cell = cell_instance->cell_ref;
|
|
|
|
if (temp_cell != NULL) {
|
2018-07-20 22:32:23 +02:00
|
|
|
apply_inherited_transform_to_all_layers(layers,
|
|
|
|
&cell_instance->origin,
|
|
|
|
cell_instance->magnification,
|
|
|
|
cell_instance->flipped,
|
|
|
|
cell_instance->angle,
|
|
|
|
scale);
|
|
|
|
render_cell(temp_cell, layers, scale);
|
|
|
|
revert_inherited_transform(layers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Render graphics */
|
|
|
|
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
|
|
|
|
gfx = (struct gds_graphics *)gfx_list->data;
|
|
|
|
|
|
|
|
/* Get layer renderer */
|
|
|
|
if (gfx->layer >= MAX_LAYERS)
|
|
|
|
continue;
|
2019-08-19 19:54:53 +02:00
|
|
|
|
|
|
|
cr = layers[gfx->layer].cr;
|
|
|
|
if (cr == NULL)
|
2018-07-20 22:32:23 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Apply settings */
|
2018-07-22 16:38:26 +02:00
|
|
|
cairo_set_line_width(cr, (gfx->width_absolute ? gfx->width_absolute/scale : 1));
|
2018-07-20 22:32:23 +02:00
|
|
|
|
|
|
|
switch (gfx->path_render_type) {
|
|
|
|
case PATH_FLUSH:
|
|
|
|
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
|
|
|
|
break;
|
|
|
|
case PATH_ROUNDED:
|
|
|
|
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
|
|
|
break;
|
|
|
|
case PATH_SQUARED:
|
|
|
|
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add vertices */
|
|
|
|
for (vertex_list = gfx->vertices; vertex_list != NULL; vertex_list = vertex_list->next) {
|
|
|
|
vertex = (struct gds_point *)vertex_list->data;
|
|
|
|
|
|
|
|
/* If first point -> move to, else line to */
|
|
|
|
if (vertex_list->prev == NULL)
|
|
|
|
cairo_move_to(cr, vertex->x/scale, vertex->y/scale);
|
|
|
|
else
|
|
|
|
cairo_line_to(cr, vertex->x/scale, vertex->y/scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create graphics object */
|
|
|
|
switch (gfx->gfx_type) {
|
|
|
|
case GRAPHIC_PATH:
|
|
|
|
cairo_stroke(cr);
|
|
|
|
break;
|
2018-07-20 23:29:27 +02:00
|
|
|
case GRAPHIC_BOX:
|
2019-09-18 20:38:32 +02:00
|
|
|
/* Expected fallthrough */
|
2018-07-20 22:32:23 +02:00
|
|
|
case GRAPHIC_POLYGON:
|
2018-07-22 16:38:26 +02:00
|
|
|
cairo_set_line_width(cr, 0.1/scale);
|
2018-07-20 22:32:23 +02:00
|
|
|
cairo_close_path(cr);
|
2018-07-22 16:38:26 +02:00
|
|
|
cairo_stroke_preserve(cr); // Prevent graphic glitches
|
2018-07-20 22:32:23 +02:00
|
|
|
cairo_fill(cr);
|
|
|
|
break;
|
|
|
|
}
|
2019-08-19 19:54:53 +02:00
|
|
|
} /* for gfx list */
|
2018-07-20 22:32:23 +02:00
|
|
|
}
|
|
|
|
|
2019-09-18 20:39:42 +02:00
|
|
|
/**
|
|
|
|
* @brief Read a line from a file descriptor
|
|
|
|
*
|
|
|
|
* In case of a broken pipe / closed writing end, it will terminate
|
|
|
|
*
|
|
|
|
* @param fd File descriptor to read from
|
|
|
|
* @param buff Buffer to write data in
|
|
|
|
* @param buff_size Buffer size
|
|
|
|
* @return length of read data
|
|
|
|
*/
|
|
|
|
static int read_line_from_fd(int fd, char *buff, size_t buff_size)
|
|
|
|
{
|
|
|
|
ssize_t cnt;
|
|
|
|
char c;
|
|
|
|
unsigned int buff_cnt = 0;
|
|
|
|
|
|
|
|
while ((cnt = read(fd, &c, 1)) == 1) {
|
|
|
|
if (buff_cnt < (buff_size-1)) {
|
|
|
|
buff[buff_cnt++] = c;
|
|
|
|
if (c == '\n')
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buff[buff_cnt] = 0;
|
|
|
|
return (int)buff_cnt;
|
|
|
|
}
|
|
|
|
|
2019-06-19 19:21:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Render \p cell to a PDF file specified by \p pdf_file
|
2019-09-28 23:12:14 +02:00
|
|
|
* @param renderer The current renderer this function is running from
|
2019-06-19 19:21:20 +02:00
|
|
|
* @param cell Toplevel cell to @ref Cairo-Renderer
|
|
|
|
* @param layer_infos List of layer information. Specifies color and layer stacking
|
|
|
|
* @param pdf_file PDF output file. Set to NULL if no PDF file has to be generated
|
|
|
|
* @param svg_file SVG output file. Set to NULL if no SVG file has to be generated
|
|
|
|
* @param scale Scale the output image down by \p scale
|
|
|
|
* @return Error
|
|
|
|
*/
|
2019-10-25 21:16:31 +02:00
|
|
|
static int cairo_renderer_render_cell_to_vector_file(GdsOutputRenderer *renderer,
|
|
|
|
struct gds_cell *cell,
|
|
|
|
GList *layer_infos,
|
|
|
|
const char *pdf_file,
|
|
|
|
const char *svg_file,
|
|
|
|
double scale)
|
2018-07-19 17:49:33 +02:00
|
|
|
{
|
2019-05-30 14:17:36 +02:00
|
|
|
cairo_surface_t *pdf_surface = NULL, *svg_surface = NULL;
|
|
|
|
cairo_t *pdf_cr = NULL, *svg_cr = NULL;
|
2018-07-19 18:45:37 +02:00
|
|
|
struct layer_info *linfo;
|
|
|
|
struct cairo_layer *layers;
|
|
|
|
struct cairo_layer *lay;
|
|
|
|
GList *info_list;
|
|
|
|
int i;
|
2018-07-22 16:38:26 +02:00
|
|
|
double rec_x0, rec_y0, rec_width, rec_height;
|
|
|
|
double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN;
|
2019-05-30 14:49:35 +02:00
|
|
|
pid_t process_id;
|
2019-09-19 21:42:55 +02:00
|
|
|
int comm_pipe[2];
|
|
|
|
char receive_message[200];
|
2018-07-19 18:45:37 +02:00
|
|
|
|
2018-07-30 12:35:30 +02:00
|
|
|
if (pdf_file == NULL && svg_file == NULL) {
|
|
|
|
/* No output specified */
|
2019-06-19 19:21:20 +02:00
|
|
|
return -1;
|
2018-07-30 12:35:30 +02:00
|
|
|
}
|
|
|
|
|
2019-09-19 21:42:55 +02:00
|
|
|
/* Generate communication pipe for status updates */
|
|
|
|
if (pipe(comm_pipe) == -1)
|
|
|
|
return -2;
|
|
|
|
|
2019-05-30 14:49:35 +02:00
|
|
|
/* Fork to a new child process. This ensures the memory leaks (see issue #16) in Cairo don't
|
|
|
|
* brick everything.
|
|
|
|
*
|
|
|
|
* And by the way: This now bricks all Windows compatibility. Deal with it.
|
|
|
|
*/
|
|
|
|
process_id = fork();
|
2019-08-20 19:01:03 +02:00
|
|
|
//process_id = -1;
|
2019-05-30 14:49:35 +02:00
|
|
|
if (process_id < 0) {
|
2019-09-19 21:42:55 +02:00
|
|
|
/* This should not happen */
|
2019-12-12 21:22:14 +01:00
|
|
|
fprintf(stderr, _("Fatal error: Cairo Renderer: Could not spawn child process!"));
|
2019-09-19 21:42:55 +02:00
|
|
|
exit(-2);
|
2019-05-30 14:49:35 +02:00
|
|
|
} else if (process_id > 0) {
|
2019-05-30 14:55:37 +02:00
|
|
|
/* Woohoo... Successfully dumped the shitty code to an unknowing victim */
|
2019-05-30 14:49:35 +02:00
|
|
|
goto ret_parent;
|
|
|
|
}
|
|
|
|
|
2020-01-14 14:09:24 +01:00
|
|
|
/* We are now in a separate process just for rendering the output image.
|
|
|
|
* You may print a log message to the activity bar of the gui by writing a line
|
|
|
|
* teminated with '\n' to comm_pipe[1]. This will be handled by the parent process.
|
|
|
|
* Directly calling the update function
|
|
|
|
* gds_output_renderer_update_async_progress()
|
|
|
|
* does not have any effect because this is a separate process.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Close stdin and (stdout and stderr may live on)
|
|
|
|
*/
|
2019-09-19 21:42:55 +02:00
|
|
|
close(0);
|
|
|
|
close(comm_pipe[0]);
|
|
|
|
|
2018-07-19 18:45:37 +02:00
|
|
|
layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer));
|
|
|
|
|
|
|
|
/* Clear layers */
|
|
|
|
for (i = 0; i < MAX_LAYERS; i++) {
|
|
|
|
layers[i].cr = NULL;
|
|
|
|
layers[i].rec = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create recording surface for each layer */
|
|
|
|
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
|
|
|
linfo = (struct layer_info *)info_list->data;
|
2019-08-20 19:01:03 +02:00
|
|
|
if (linfo->layer < MAX_LAYERS) {
|
|
|
|
/* Layer shall not be rendered */
|
|
|
|
if (!linfo->render)
|
|
|
|
continue;
|
|
|
|
|
2018-07-19 18:45:37 +02:00
|
|
|
lay = &(layers[(unsigned int)linfo->layer]);
|
|
|
|
lay->linfo = linfo;
|
|
|
|
lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,
|
|
|
|
NULL);
|
|
|
|
lay->cr = cairo_create(layers[(unsigned int)linfo->layer].rec);
|
2018-07-20 22:32:23 +02:00
|
|
|
cairo_scale(lay->cr, 1, -1); // Fix coordinate system
|
2018-07-22 16:38:26 +02:00
|
|
|
cairo_set_source_rgb(lay->cr, linfo->color.red, linfo->color.green, linfo->color.blue);
|
2018-07-19 18:45:37 +02:00
|
|
|
} else {
|
|
|
|
printf("Layer number (%d) too high!\n", linfo->layer);
|
|
|
|
goto ret_clear_layers;
|
|
|
|
}
|
|
|
|
}
|
2018-07-19 17:49:33 +02:00
|
|
|
|
2019-09-19 21:42:55 +02:00
|
|
|
dprintf(comm_pipe[1], "Rendering layers\n");
|
2018-07-20 22:32:23 +02:00
|
|
|
render_cell(cell, layers, scale);
|
|
|
|
|
2018-07-22 16:38:26 +02:00
|
|
|
/* get size of image and top left coordinate */
|
|
|
|
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
|
|
|
linfo = (struct layer_info *)info_list->data;
|
|
|
|
|
|
|
|
if (linfo->layer >= MAX_LAYERS) {
|
2019-12-12 21:22:14 +01:00
|
|
|
printf(_("Layer number too high / outside of spec.\n"));
|
2018-07-22 16:38:26 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-06-21 21:41:31 +02:00
|
|
|
if (!linfo->render)
|
|
|
|
continue;
|
|
|
|
|
2018-07-22 16:38:26 +02:00
|
|
|
/* Print size */
|
|
|
|
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
|
|
|
|
&rec_width, &rec_height);
|
2019-12-12 21:22:14 +01:00
|
|
|
dprintf(comm_pipe[1], _("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n"),
|
2019-03-22 22:15:56 +01:00
|
|
|
linfo->layer,
|
|
|
|
(linfo->name && linfo->name[0] ? " (" : ""),
|
|
|
|
(linfo->name && linfo->name[0] ? linfo->name : ""),
|
|
|
|
(linfo->name && linfo->name[0] ? ")" : ""),
|
|
|
|
rec_width, rec_height, rec_x0, rec_y0);
|
2018-07-22 16:38:26 +02:00
|
|
|
|
|
|
|
/* update bounding box */
|
|
|
|
xmin = MIN(xmin, rec_x0);
|
|
|
|
xmax = MAX(xmax, rec_x0);
|
|
|
|
ymin = MIN(ymin, rec_y0);
|
|
|
|
ymax = MAX(ymax, rec_y0);
|
|
|
|
xmin = MIN(xmin, rec_x0+rec_width);
|
|
|
|
xmax = MAX(xmax, rec_x0+rec_width);
|
|
|
|
ymin = MIN(ymin, rec_y0+rec_height);
|
|
|
|
ymax = MAX(ymax, rec_y0+rec_height);
|
|
|
|
|
|
|
|
}
|
2018-07-20 22:32:23 +02:00
|
|
|
|
2019-09-19 21:42:55 +02:00
|
|
|
/* printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); */
|
2018-07-22 16:38:26 +02:00
|
|
|
|
2018-07-30 12:35:30 +02:00
|
|
|
if (pdf_file) {
|
|
|
|
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);
|
|
|
|
pdf_cr = cairo_create(pdf_surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (svg_file) {
|
2018-08-01 12:36:31 +02:00
|
|
|
svg_surface = cairo_svg_surface_create(svg_file, xmax-xmin, ymax-ymin);
|
2018-07-30 12:35:30 +02:00
|
|
|
svg_cr = cairo_create(svg_surface);
|
|
|
|
}
|
2018-07-22 16:38:26 +02:00
|
|
|
|
|
|
|
/* Write layers to PDF */
|
|
|
|
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
|
|
|
linfo = (struct layer_info *)info_list->data;
|
|
|
|
|
2019-12-12 21:22:14 +01:00
|
|
|
dprintf(comm_pipe[1], _("Exporting layer %d to file\n"), linfo->layer);
|
2019-09-19 21:42:55 +02:00
|
|
|
|
2018-07-22 16:38:26 +02:00
|
|
|
if (linfo->layer >= MAX_LAYERS) {
|
2019-12-12 21:22:14 +01:00
|
|
|
printf(_("Layer outside of spec.\n"));
|
2018-07-22 16:38:26 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-06-21 21:41:31 +02:00
|
|
|
if (!linfo->render)
|
|
|
|
continue;
|
|
|
|
|
2019-05-30 14:17:36 +02:00
|
|
|
if (pdf_file && pdf_cr) {
|
2018-07-30 12:35:30 +02:00
|
|
|
cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
|
|
|
cairo_paint_with_alpha(pdf_cr, linfo->color.alpha);
|
|
|
|
}
|
|
|
|
|
2019-05-30 14:17:36 +02:00
|
|
|
if (svg_file && svg_cr) {
|
2018-07-30 12:35:30 +02:00
|
|
|
cairo_set_source_surface(svg_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
|
|
|
cairo_paint_with_alpha(svg_cr, linfo->color.alpha);
|
|
|
|
}
|
2018-07-22 16:38:26 +02:00
|
|
|
}
|
|
|
|
|
2018-07-30 12:35:30 +02:00
|
|
|
if (pdf_file) {
|
|
|
|
cairo_show_page(pdf_cr);
|
|
|
|
cairo_destroy(pdf_cr);
|
|
|
|
cairo_surface_destroy(pdf_surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (svg_file) {
|
|
|
|
cairo_show_page(svg_cr);
|
|
|
|
cairo_destroy(svg_cr);
|
|
|
|
cairo_surface_destroy(svg_surface);
|
|
|
|
}
|
2018-07-20 22:32:23 +02:00
|
|
|
|
2018-07-19 18:45:37 +02:00
|
|
|
ret_clear_layers:
|
|
|
|
for (i = 0; i < MAX_LAYERS; i++) {
|
|
|
|
lay = &layers[i];
|
2019-10-25 21:16:31 +02:00
|
|
|
if (lay->cr) {
|
2018-07-22 16:38:26 +02:00
|
|
|
cairo_destroy(lay->cr);
|
|
|
|
cairo_surface_destroy(lay->rec);
|
|
|
|
}
|
2018-07-19 18:45:37 +02:00
|
|
|
}
|
|
|
|
free(layers);
|
2018-07-19 17:49:33 +02:00
|
|
|
|
2019-12-12 21:22:14 +01:00
|
|
|
printf(_("Cairo export finished. It might still be buggy!\n"));
|
2019-05-30 14:49:35 +02:00
|
|
|
|
2019-09-19 21:42:55 +02:00
|
|
|
/* Suspend child process */
|
|
|
|
exit(0);
|
2019-05-30 14:49:35 +02:00
|
|
|
|
|
|
|
ret_parent:
|
2019-09-19 21:42:55 +02:00
|
|
|
close(comm_pipe[1]);
|
|
|
|
|
|
|
|
while (read_line_from_fd(comm_pipe[0], receive_message, sizeof(receive_message)) > 0) {
|
|
|
|
/* Strip \n from string and replace with ' ' */
|
|
|
|
for (i = 0; receive_message[i] != '\0'; i++) {
|
|
|
|
if (receive_message[i] == '\n')
|
|
|
|
receive_message[i] = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update asyc progress*/
|
2019-09-19 21:44:30 +02:00
|
|
|
gds_output_renderer_update_async_progress(renderer, receive_message);
|
2019-09-19 21:42:55 +02:00
|
|
|
}
|
|
|
|
|
2019-05-30 14:49:35 +02:00
|
|
|
waitpid(process_id, NULL, 0);
|
2019-09-19 21:42:55 +02:00
|
|
|
|
|
|
|
close(comm_pipe[0]);
|
2019-06-19 19:21:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cairo_renderer_init(CairoRenderer *self)
|
|
|
|
{
|
|
|
|
/* PDF default */
|
|
|
|
self->svg = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cairo_renderer_render_output(GdsOutputRenderer *renderer,
|
|
|
|
struct gds_cell *cell,
|
|
|
|
double scale)
|
|
|
|
{
|
|
|
|
CairoRenderer *c_renderer = GDS_RENDER_CAIRO_RENDERER(renderer);
|
|
|
|
const char *pdf_file = NULL;
|
|
|
|
const char *svg_file = NULL;
|
2019-06-21 21:41:31 +02:00
|
|
|
LayerSettings *settings;
|
|
|
|
GList *layer_infos = NULL;
|
|
|
|
const char *output_file;
|
2019-08-19 19:54:53 +02:00
|
|
|
int ret;
|
2019-06-19 19:21:20 +02:00
|
|
|
|
|
|
|
if (!c_renderer)
|
|
|
|
return -2000;
|
|
|
|
|
2019-06-21 21:41:31 +02:00
|
|
|
output_file = gds_output_renderer_get_output_file(renderer);
|
2019-08-19 19:54:53 +02:00
|
|
|
settings = gds_output_renderer_get_and_ref_layer_settings(renderer);
|
2019-06-21 21:41:31 +02:00
|
|
|
|
|
|
|
/* Set layer info list. In case of failure it remains NULL */
|
|
|
|
if (settings)
|
|
|
|
layer_infos = layer_settings_get_layer_info_list(settings);
|
|
|
|
|
2019-06-19 19:21:20 +02:00
|
|
|
if (c_renderer->svg == TRUE)
|
|
|
|
svg_file = output_file;
|
|
|
|
else
|
|
|
|
pdf_file = output_file;
|
|
|
|
|
2019-12-12 21:22:14 +01:00
|
|
|
gds_output_renderer_update_async_progress(renderer, _("Rendering Cairo Output..."));
|
2019-09-19 21:42:55 +02:00
|
|
|
ret = cairo_renderer_render_cell_to_vector_file(renderer, cell, layer_infos, pdf_file, svg_file, scale);
|
2019-08-19 19:54:53 +02:00
|
|
|
|
|
|
|
if (settings)
|
|
|
|
g_object_unref(settings);
|
|
|
|
|
|
|
|
return ret;
|
2019-06-19 19:21:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cairo_renderer_class_init(CairoRendererClass *klass)
|
|
|
|
{
|
|
|
|
GdsOutputRendererClass *renderer_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
|
|
|
|
|
|
|
|
renderer_class->render_output = cairo_renderer_render_output;
|
|
|
|
}
|
|
|
|
|
|
|
|
CairoRenderer *cairo_renderer_new_pdf()
|
|
|
|
{
|
|
|
|
CairoRenderer *renderer;
|
|
|
|
|
|
|
|
renderer = GDS_RENDER_CAIRO_RENDERER(g_object_new(GDS_RENDER_TYPE_CAIRO_RENDERER, NULL));
|
|
|
|
renderer->svg = FALSE;
|
|
|
|
|
|
|
|
return renderer;
|
|
|
|
}
|
|
|
|
|
|
|
|
CairoRenderer *cairo_renderer_new_svg()
|
|
|
|
{
|
|
|
|
CairoRenderer *renderer;
|
|
|
|
|
|
|
|
renderer = GDS_RENDER_CAIRO_RENDERER(g_object_new(GDS_RENDER_TYPE_CAIRO_RENDERER, NULL));
|
|
|
|
renderer->svg = TRUE;
|
|
|
|
|
|
|
|
return renderer;
|
2018-07-19 17:49:33 +02:00
|
|
|
}
|
2018-07-24 14:42:28 +02:00
|
|
|
|
|
|
|
/** @} */
|