- char *text,
- int rotation)
-{
-
- int error;
- double text_width = 0;
- FT_Face face;
- FT_Library library = NULL;
- gfx_string string;
-
- FT_Init_FreeType(&library);
- error = FT_New_Face(library, font, 0, &face);
- if (error) {
- FT_Done_FreeType(library);
- return -1;
- }
- error = FT_Set_Char_Size(face, size * 64, size * 64, 100, 100);
- if (error) {
- FT_Done_FreeType(library);
- return -1;
- }
- string = gfx_string_create(canvas, face, text, rotation, tabwidth, size);
- text_width = string->width;
- gfx_string_destroy(string);
- FT_Done_FreeType(library);
- return text_width / 64;
-}
-
-static void gfx_libart_close_path(
- gfx_node_t *node,
- ArtVpath ** vec)
-{
- /* libart must have end==start for closed paths,
- even if using ART_MOVETO and not ART_MOVETO_OPEN
- so add extra point which is the same as the starting point */
- int points_max = node->points; /* scaled array has exact size */
- int points = node->points - 1;
-
- art_vpath_add_point(vec, &points, &points_max, ART_LINETO,
- (**vec).x, (**vec).y);
- art_vpath_add_point(vec, &points, &points_max, ART_END, 0, 0);
-}
-
-
-/* find bbox of a string */
-static void compute_string_bbox(
- gfx_string string)
-{
- unsigned int n;
- FT_BBox bbox;
-
- bbox.xMin = bbox.yMin = 32000;
- bbox.xMax = bbox.yMax = -32000;
- for (n = 0; n < string->num_glyphs; n++) {
- FT_BBox glyph_bbox;
-
- FT_Glyph_Get_CBox(string->glyphs[n].image, ft_glyph_bbox_gridfit,
- &glyph_bbox);
- if (glyph_bbox.xMin < bbox.xMin) {
- bbox.xMin = glyph_bbox.xMin;
- }
- if (glyph_bbox.yMin < bbox.yMin) {
- bbox.yMin = glyph_bbox.yMin;
- }
- if (glyph_bbox.xMax > bbox.xMax) {
- bbox.xMax = glyph_bbox.xMax;
- }
- if (glyph_bbox.yMax > bbox.yMax) {
- bbox.yMax = glyph_bbox.yMax;
- }
- }
- if (bbox.xMin > bbox.xMax) {
- bbox.xMin = 0;
- bbox.yMin = 0;
- bbox.xMax = 0;
- bbox.yMax = 0;
- }
- string->bbox.xMin = bbox.xMin;
- string->bbox.xMax = bbox.xMax;
- string->bbox.yMin = bbox.yMin;
- string->bbox.yMax = bbox.yMax;
-}
-
-/* create a free type glyph string */
-gfx_string gfx_string_create(
- gfx_canvas_t *canvas,
- FT_Face face,
- const char *text,
- int rotation,
- double tabwidth,
- double size)
-{
-
- FT_GlyphSlot slot = face->glyph; /* a small shortcut */
- FT_Bool use_kerning;
- FT_UInt previous;
- FT_Vector ft_pen;
-
- gfx_string string = (gfx_string) malloc(sizeof(struct gfx_string_s));
-
- gfx_char glyph; /* current glyph in table */
- int n;
- int error;
- int gottab = 0;
-
-#ifdef HAVE_MBSTOWCS
- wchar_t *cstr;
- size_t clen = strlen(text) + 1;
-
- cstr = malloc(sizeof(wchar_t) * clen); /* yes we are allocating probably too much here, I know */
- string->count = mbstowcs(cstr, text, clen);
- if (string->count == -1) {
- /* conversion did not work, so lets fall back to just use what we got */
- string->count = clen - 1;
- for (n = 0; text[n] != '\0'; n++) {
- cstr[n] = (unsigned char) text[n];
- }
- }
-#else
- char *cstr = strdup(text);
-
- string->count = strlen(text);
-#endif
-
- ft_pen.x = 0; /* start at (0,0) !! */
- ft_pen.y = 0;
-
-
- string->width = 0;
- string->height = 0;
- string->glyphs =
- (gfx_char) calloc(string->count, sizeof(struct gfx_char_s));
- string->num_glyphs = 0;
- string->transform.xx =
- (FT_Fixed) (cos(M_PI * (rotation) / 180.0) * 0x10000);
- string->transform.xy =
- (FT_Fixed) (-sin(M_PI * (rotation) / 180.0) * 0x10000);
- string->transform.yx =
- (FT_Fixed) (sin(M_PI * (rotation) / 180.0) * 0x10000);
- string->transform.yy =
- (FT_Fixed) (cos(M_PI * (rotation) / 180.0) * 0x10000);
-
- use_kerning = FT_HAS_KERNING(face);
- previous = 0;
- glyph = string->glyphs;
- for (n = 0; n < string->count; glyph++, n++) {
- FT_Vector vec;
-
- /* handle the tabs ...
- have a witespace glyph inserted, but set its width such that the distance
- of the new right edge is x times tabwidth from 0,0 where x is an integer. */
- unsigned int letter = cstr[n];
-
- letter = afm_fix_osx_charset(letter); /* unsafe macro */
-
- gottab = 0;
- if (letter == '\\' && n + 1 < string->count && cstr[n + 1] == 't') {
- /* we have a tab here so skip the backslash and
- set t to ' ' so that we get a white space */
- gottab = 1;
- n++;
- letter = ' ';
- }
- if (letter == '\t') {
- letter = ' ';
- gottab = 1;
- }
- /* initialize each struct gfx_char_s */
- glyph->index = 0;
- glyph->pos.x = 0;
- glyph->pos.y = 0;
- glyph->image = NULL;
- glyph->index = FT_Get_Char_Index(face, letter);
-
- /* compute glyph origin */
- if (use_kerning && previous && glyph->index) {
- FT_Vector kerning;
-
- FT_Get_Kerning(face, previous, glyph->index,
- ft_kerning_default, &kerning);
- ft_pen.x += kerning.x;
- ft_pen.y += kerning.y;
- }
-
- /* load the glyph image (in its native format) */
- /* for now, we take a monochrome glyph bitmap */
- error =
- FT_Load_Glyph(face, glyph->index,
- size >
- canvas->font_aa_threshold ? canvas->aa_type ==
- AA_NORMAL ? FT_LOAD_TARGET_NORMAL : canvas->
- aa_type ==
- AA_LIGHT ? FT_LOAD_TARGET_LIGHT :
- FT_LOAD_TARGET_MONO : FT_LOAD_TARGET_MONO);
- if (error) {
- RRDPRINTF("couldn't load glyph: %c\n", letter)
- continue;
- }
- error = FT_Get_Glyph(slot, &glyph->image);
- if (error) {
- RRDPRINTF("couldn't get glyph %c from slot %d\n", letter,
- (int) slot)
- continue;
- }
- /* if we are in tabbing mode, we replace the tab with a space and shift the position
- of the space so that its left edge is where the tab was supposed to land us */
- if (gottab) {
- /* we are in gridfitting mode so the calculations happen in 1/64 pixles */
- ft_pen.x =
- tabwidth * 64.0 * (float) (1 +
- (long) (ft_pen.x /
- (tabwidth * 64.0))) -
- slot->advance.x;
- }
- /* store current pen position */
- glyph->pos.x = ft_pen.x;
- glyph->pos.y = ft_pen.y;
-
-
- ft_pen.x += slot->advance.x;
- ft_pen.y += slot->advance.y;
-
- /* rotate glyph */
- vec = glyph->pos;
- FT_Vector_Transform(&vec, &string->transform);
- error = FT_Glyph_Transform(glyph->image, &string->transform, &vec);
- if (error) {
- RRDPRINTF("couldn't transform glyph id %d\n", letter)
- continue;
- }
-
- /* convert to a bitmap - destroy native image */
- error =
- FT_Glyph_To_Bitmap(&glyph->image,
- size >
- canvas->font_aa_threshold ? canvas->aa_type ==
- AA_NORMAL ? FT_RENDER_MODE_NORMAL : canvas->
- aa_type ==
- AA_LIGHT ? FT_RENDER_MODE_LIGHT :
- FT_RENDER_MODE_MONO : FT_RENDER_MODE_MONO, 0,
- 1);
- if (error) {
- RRDPRINTF("couldn't convert glyph id %d to bitmap\n", letter)
- continue;
- }
-
- /* increment number of glyphs */
- previous = glyph->index;
- string->num_glyphs++;
- }
- free(cstr);
-/* printf ("number of glyphs = %d\n", string->num_glyphs);*/
- compute_string_bbox(string);
- /* the last character was a tab */
- /* if (gottab) { */
- string->width = ft_pen.x;
- /* } else {
- string->width = string->bbox.xMax - string->bbox.xMin;
- } */
- string->height = string->bbox.yMax - string->bbox.yMin;
- return string;
-}
-
-
-static int gfx_save_png(
- art_u8 * buffer,
- FILE * fp,
- long width,
- long height,
- long bytes_per_pixel);
-
-/* render grafics into png image */
-
-int gfx_render_png(
- gfx_canvas_t *canvas,
- art_u32 width,
- art_u32 height,
- gfx_color_t background,
- FILE * fp)
-{
-
-
- FT_Library library;
- gfx_node_t *node = canvas->firstnode;
-
- /*
- art_u8 red = background >> 24, green = (background >> 16) & 0xff;
- art_u8 blue = (background >> 8) & 0xff, alpha = ( background & 0xff );
- */
- unsigned long pys_width = width * canvas->zoom;
- unsigned long pys_height = height * canvas->zoom;
- const int bytes_per_pixel = 4;
- unsigned long rowstride = pys_width * bytes_per_pixel; /* bytes per pixel */
-
- /* fill that buffer with out background color */
- gfx_color_t *buffp = art_new(gfx_color_t, pys_width * pys_height);
- art_u8 *buffer = (art_u8 *) buffp;
- unsigned long i;
-
- for (i = 0; i < pys_width * pys_height; i++) {
- *(buffp++) = background;
- }
- FT_Init_FreeType(&library);
- while (node) {
- switch (node->type) {
- case GFX_LINE:
- case GFX_AREA:{
- ArtVpath *vec;
- double dst[6];
- ArtSVP *svp;
-
- art_affine_scale(dst, canvas->zoom, canvas->zoom);
- vec = art_vpath_affine_transform(node->path, dst);
- if (node->closed_path)
- gfx_libart_close_path(node, &vec);
- /* gfx_round_scaled_coordinates(vec); */
- /* pvec = art_vpath_perturb(vec);
- art_free(vec); */
- if (node->type == GFX_LINE) {
- svp = art_svp_vpath_stroke(vec, ART_PATH_STROKE_JOIN_ROUND,
- ART_PATH_STROKE_CAP_ROUND,
- node->size * canvas->zoom, 4,
- 0.25);
- } else {
- svp = art_svp_from_vpath(vec);
- /* this takes time and is unnecessary since we make
- sure elsewhere that the areas are going clock-whise */
- /* svpt = art_svp_uncross( svp );
- art_svp_free(svp);
- svp = art_svp_rewind_uncrossed(svpt,ART_WIND_RULE_NONZERO);
- art_svp_free(svpt);
- */
- }
- art_free(vec);
- /* this is from gnome since libart does not have this yet */
- gnome_print_art_rgba_svp_alpha(svp, 0, 0, pys_width, pys_height,
- node->color, buffer, rowstride,
- NULL);
- art_svp_free(svp);
- break;
- }
- case GFX_TEXT:{
- unsigned int n;
- int error;
- art_u8 fcolor[4], falpha;
- FT_Face face;
- gfx_char glyph;
- gfx_string string;
- FT_Vector vec; /* 26.6 */
-
- float pen_x = 0.0, pen_y = 0.0;
-
- /* double x,y; */
- long ix, iy;
-
- fcolor[0] = node->color >> 24;
- fcolor[1] = (node->color >> 16) & 0xff;
- fcolor[2] = (node->color >> 8) & 0xff;
- falpha = node->color & 0xff;
- error = FT_New_Face(library, (char *) node->filename, 0, &face);
- if (error) {
- rrd_set_error("failed to load %s", node->filename);
-
- break;
- }
- error = FT_Set_Char_Size(face, /* handle to face object */
- (long) (node->size * 64),
- (long) (node->size * 64),
- (long) (100 * canvas->zoom),
- (long) (100 * canvas->zoom));
- if (error) {
- FT_Done_Face(face);
- break;
- }
- pen_x = node->x * canvas->zoom;
- pen_y = node->y * canvas->zoom;
-
- string =
- gfx_string_create(canvas, face, node->text, node->angle,
- node->tabwidth, node->size);
- FT_Done_Face(face);
-
- switch (node->halign) {
- case GFX_H_RIGHT:
- vec.x = -string->bbox.xMax;
- break;
- case GFX_H_CENTER:
- vec.x = abs(string->bbox.xMax) >= abs(string->bbox.xMin) ?
- -string->bbox.xMax / 2 : -string->bbox.xMin / 2;
- break;
- case GFX_H_LEFT:
- vec.x = -string->bbox.xMin;
- break;
- case GFX_H_NULL:
- vec.x = 0;
- break;
- }
-
- switch (node->valign) {
- case GFX_V_TOP:
- vec.y = string->bbox.yMax;
- break;
- case GFX_V_CENTER:
- vec.y = abs(string->bbox.yMax) >= abs(string->bbox.yMin) ?
- string->bbox.yMax / 2 : string->bbox.yMin / 2;
- break;
- case GFX_V_BOTTOM:
- vec.y = 0;
- break;
- case GFX_V_NULL:
- vec.y = 0;
- break;
- }
- pen_x += vec.x / 64;
- pen_y += vec.y / 64;
- glyph = string->glyphs;
- for (n = 0; n < string->num_glyphs; n++, glyph++) {
- int gr;
- FT_Glyph image;
- FT_BitmapGlyph bit;
-
- /* long buf_x,comp_n; */
- /* make copy to transform */
- if (!glyph->image) {
- RRDPRINTF("no image\n")
- continue;
- }
- error = FT_Glyph_Copy(glyph->image, &image);
- if (error) {
- RRDPRINTF("couldn't copy image\n")
- continue;
- }
-
- /* transform it */
- vec = glyph->pos;
- FT_Vector_Transform(&vec, &string->transform);
-
- bit = (FT_BitmapGlyph) image;
- gr = bit->bitmap.num_grays - 1;
-/*
- buf_x = (pen_x + 0.5) + (double)bit->left;
- comp_n = buf_x + bit->bitmap.width > pys_width ? pys_width - buf_x : bit->bitmap.width;
- if (buf_x < 0 || buf_x >= (long)pys_width) continue;
- buf_x *= bytes_per_pixel ;
- for (iy=0; iy < bit->bitmap.rows; iy++){
- long buf_y = iy+(pen_y+0.5)-(double)bit->top;
- if (buf_y < 0 || buf_y >= (long)pys_height) continue;
- buf_y *= rowstride;
- for (ix=0;ix < bit->bitmap.width;ix++){
- *(letter + (ix*bytes_per_pixel+3)) = *(bit->bitmap.buffer + iy * bit->bitmap.width + ix);
- }
- art_rgba_rgba_composite(buffer + buf_y + buf_x ,letter,comp_n);
- }
- art_free(letter);
-*/
- switch (bit->bitmap.pixel_mode) {
- case FT_PIXEL_MODE_GRAY:
- for (iy = 0; iy < bit->bitmap.rows; iy++) {
- long buf_y = iy + (pen_y + 0.5) - bit->top;
-
- if (buf_y < 0 || buf_y >= (long) pys_height)
- continue;
- buf_y *= rowstride;
- for (ix = 0; ix < bit->bitmap.width; ix++) {
- long buf_x =
- ix + (pen_x + 0.5) + (double) bit->left;
- art_u8 font_alpha;
-
- if (buf_x < 0 || buf_x >= (long) pys_width)
- continue;
- buf_x *= bytes_per_pixel;
- font_alpha =
- *(bit->bitmap.buffer +
- iy * bit->bitmap.pitch + ix);
- if (font_alpha > 0) {
- fcolor[3] =
- (art_u8) ((double) font_alpha / gr *
- falpha);
- art_rgba_rgba_composite(buffer + buf_y +
- buf_x, fcolor, 1);
- }
- }
- }
- break;
-
- case FT_PIXEL_MODE_MONO:
- for (iy = 0; iy < bit->bitmap.rows; iy++) {
- long buf_y = iy + (pen_y + 0.5) - bit->top;
-
- if (buf_y < 0 || buf_y >= (long) pys_height)
- continue;
- buf_y *= rowstride;
- for (ix = 0; ix < bit->bitmap.width; ix++) {
- long buf_x =
- ix + (pen_x + 0.5) + (double) bit->left;
-
- if (buf_x < 0 || buf_x >= (long) pys_width)
- continue;
- buf_x *= bytes_per_pixel;
- if ((fcolor[3] =
- falpha *
- ((*
- (bit->bitmap.buffer +
- iy * bit->bitmap.pitch + ix / 8) >> (7 -
- (ix %
- 8)))
- & 1)) > 0)
- art_rgba_rgba_composite(buffer + buf_y +
- buf_x, fcolor, 1);
- }
- }
- break;
-
- default:
- rrd_set_error("unknown freetype pixel mode: %d",
- bit->bitmap.pixel_mode);
- break;
- }
-
-/*
- for (iy=0; iy < bit->bitmap.rows; iy++){
- long buf_y = iy+(pen_y+0.5)-bit->top;
- if (buf_y < 0 || buf_y >= (long)pys_height) continue;
- buf_y *= rowstride;
- for (ix=0;ix < bit->bitmap.width;ix++){
- long buf_x = ix + (pen_x + 0.5) + (double)bit->left ;
- art_u8 font_alpha;
-
- if (buf_x < 0 || buf_x >= (long)pys_width) continue;
- buf_x *= bytes_per_pixel ;
- font_alpha = *(bit->bitmap.buffer + iy * bit->bitmap.width + ix);
- font_alpha = (art_u8)((double)font_alpha / gr * falpha);
- for (iz = 0; iz < 3; iz++){
- art_u8 *orig = buffer + buf_y + buf_x + iz;
- *orig = (art_u8)((double)*orig / gr * ( gr - font_alpha) +
- (double)fcolor[iz] / gr * (font_alpha));
- }
- }
- }
-*/
- FT_Done_Glyph(image);
- }
- gfx_string_destroy(string);
- }
- }
- node = node->next;
- }
- gfx_save_png(buffer, fp, pys_width, pys_height, bytes_per_pixel);
- art_free(buffer);
- FT_Done_FreeType(library);
- return 0;
-}
-
-/* free memory used by nodes this will also remove memory required for
- associated paths and svcs ... but not for text strings */
-int gfx_destroy(
- gfx_canvas_t *canvas)
-{
- gfx_node_t *next, *node = canvas->firstnode;
-
- while (node) {
- next = node->next;
- art_free(node->path);
- free(node->text);
- free(node->filename);
- art_free(node);
- node = next;
- }
- art_free(canvas);
- return 0;
-}
-
-static int gfx_save_png(
- art_u8 * buffer,
- FILE * fp,
- long width,
- long height,
- long bytes_per_pixel)
-{
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- int i;
- png_bytep *row_pointers;
- int rowstride = width * bytes_per_pixel;
- png_text text[2];
-
- if (fp == NULL)
- return (1);
-
- png_ptr =
- png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png_ptr == NULL) {
- return (1);
- }
- row_pointers = (png_bytepp) png_malloc(png_ptr,
- height * sizeof(png_bytep));
-
- info_ptr = png_create_info_struct(png_ptr);
-
- if (info_ptr == NULL) {
- png_free(png_ptr, row_pointers);
- png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
- return (1);
- }
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- /* If we get here, we had a problem writing the file */
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return (1);
- }
-
- png_init_io(png_ptr, fp);
- png_set_IHDR(png_ptr, info_ptr, width, height,
- 8, PNG_COLOR_TYPE_RGB_ALPHA,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-
- text[0].key = "Software";
- text[0].text =
- "RRDtool, Tobias Oetiker <tobi@oetike.ch>, http://tobi.oetiker.ch";
- text[0].compression = PNG_TEXT_COMPRESSION_NONE;
- png_set_text(png_ptr, info_ptr, text, 1);
-
- /* lets make this fast while ending up with some increass in image size */
- png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
- /* png_set_filter(png_ptr,0,PNG_FILTER_SUB); */
- png_set_compression_level(png_ptr, 1);
- /* png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY); */
- /*
- png_set_filter(png_ptr,PNG_FILTER_TYPE_BASE,PNG_FILTER_SUB);
- png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY);
- png_set_compression_level(png_ptr,Z_BEST_SPEED); */
-
- /* Write header data */
- png_write_info(png_ptr, info_ptr);
- for (i = 0; i < height; i++)
- row_pointers[i] = (png_bytep) (buffer + i * rowstride);
-
- png_write_image(png_ptr, row_pointers);
- png_write_end(png_ptr, info_ptr);
- png_free(png_ptr, row_pointers);
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return 1;
-}
-
-
-/* ----- COMMON ROUTINES for pdf, svg and eps */
-#define min3(a, b, c) (a < b ? (a < c ? a : c) : (b < c ? b : c))
-#define max3(a, b, c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
-
-#define PDF_CALC_DEBUG 0
-
-typedef struct pdf_point {
- double x, y;
-} pdf_point;
-
-typedef struct {
- double ascender, descender, baselineY;
- pdf_point sizep, minp, maxp;
- double x, y, tdx, tdy;
- double r, cos_r, sin_r;
- double ma, mb, mc, md, mx, my; /* pdf coord matrix */
- double tmx, tmy; /* last 2 coords of text coord matrix */
-#if PDF_CALC_DEBUG
- int debug;
-#endif
-} pdf_coords;
-
-#if PDF_CALC_DEBUG
-static void pdf_dump_calc(
- gfx_node_t *node,
- pdf_coords * g)
-{
- fprintf(stderr, "PDF CALC =============================\n");
- fprintf(stderr, " '%s' at %f pt\n", node->text, node->size);
- fprintf(stderr, " align h = %s, v = %s, sizep = %f, %f\n",
- (node->halign == GFX_H_RIGHT ? "r" :
- (node->halign == GFX_H_CENTER ? "c" :
- (node->halign == GFX_H_LEFT ? "l" : "N"))),
- (node->valign == GFX_V_TOP ? "t" :
- (node->valign == GFX_V_CENTER ? "c" :
- (node->valign == GFX_V_BOTTOM ? "b" : "N"))),
- g->sizep.x, g->sizep.y);
- fprintf(stderr, " r = %f = %f, cos = %f, sin = %f\n",
- g->r, node->angle, g->cos_r, g->sin_r);
- fprintf(stderr, " ascender = %f, descender = %f, baselineY = %f\n",
- g->ascender, g->descender, g->baselineY);
- fprintf(stderr, " sizep: %f, %f\n", g->sizep.x, g->sizep.y);
- fprintf(stderr, " minp: %f, %f maxp = %f, %f\n",
- g->minp.x, g->minp.y, g->maxp.x, g->maxp.y);
- fprintf(stderr, " x = %f, y = %f\n", g->x, g->y);
- fprintf(stderr, " tdx = %f, tdy = %f\n", g->tdx, g->tdy);
- fprintf(stderr, " GM = %f, %f, %f, %f, %f, %f\n",
- g->ma, g->mb, g->mc, g->md, g->mx, g->my);
- fprintf(stderr, " TM = %f, %f, %f, %f, %f, %f\n",
- g->ma, g->mb, g->mc, g->md, g->tmx, g->tmy);
-}
-#endif
-
-#if PDF_CALC_DEBUG
-#define PDF_DD(x) if (g->debug) x;
-#else
-#define PDF_DD(x)
-#endif
-
-static void pdf_rotate(
- pdf_coords * g,
- pdf_point *p)
-{
- double x2 = g->cos_r * p->x - g->sin_r * p->y;
- double y2 = g->sin_r * p->x + g->cos_r * p->y;
-
- PDF_DD(fprintf
- (stderr, " rotate(%f, %f) -> %f, %f\n", p->x, p->y, x2, y2))
- p->x = x2;
- p->y = y2;
-}
-
-
-static void pdf_calc(
- int page_height,
- gfx_node_t *node,
- pdf_coords * g)