2016-07-31 06:04:43 +03:00
|
|
|
/*
|
|
|
|
* cairo.c - Cairo graphics back-end
|
|
|
|
*
|
|
|
|
* Written 2016 by Werner Almesberger
|
|
|
|
* Copyright 2016 by Werner Almesberger
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <cairo/cairo.h>
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
#include "style.h"
|
2016-07-31 09:17:10 +03:00
|
|
|
#include "text.h"
|
2016-07-31 06:04:43 +03:00
|
|
|
#include "gfx.h"
|
2016-08-01 05:07:05 +03:00
|
|
|
#include "layer.h"
|
2016-07-31 06:04:43 +03:00
|
|
|
#include "cairo.h"
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
#include "style.h"
|
|
|
|
#include "text.h"
|
|
|
|
#include "fig.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
struct cairo_ctx {
|
2016-08-01 05:07:05 +03:00
|
|
|
struct layer layer; /* must be first */
|
2016-08-01 05:53:14 +03:00
|
|
|
int xo, yo;
|
|
|
|
int scale;
|
2016-07-31 06:04:43 +03:00
|
|
|
cairo_t *cr;
|
|
|
|
cairo_surface_t *s;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIG works with 1/1200 in
|
|
|
|
* KiCad works with mil
|
|
|
|
* 1 point = 1/72 in
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
static inline int cd(struct cairo_ctx *cc, int x)
|
2016-07-31 06:04:43 +03:00
|
|
|
{
|
2016-08-01 05:53:14 +03:00
|
|
|
return x / cc->scale;
|
2016-07-31 06:04:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
static inline int cx(struct cairo_ctx *cc, int x)
|
2016-07-31 09:28:08 +03:00
|
|
|
{
|
2016-08-01 05:53:14 +03:00
|
|
|
return cc->xo + x / cc->scale;
|
2016-07-31 09:28:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
static inline int xc(struct cairo_ctx *cc, int x)
|
2016-07-31 06:04:43 +03:00
|
|
|
{
|
2016-08-01 05:53:14 +03:00
|
|
|
return (x - cc->xo) * cc->scale;
|
2016-07-31 06:04:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
static inline int cy(struct cairo_ctx *cc, int y)
|
2016-07-31 06:04:43 +03:00
|
|
|
{
|
2016-08-01 05:53:14 +03:00
|
|
|
return cc->yo + y / cc->scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline float pt(struct cairo_ctx *cc, int x)
|
|
|
|
{
|
|
|
|
return cd(cc, x) * 72 * 1.5 / 1200.0;
|
2016-07-31 06:04:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void set_color(cairo_t *cr, int color)
|
|
|
|
{
|
|
|
|
uint32_t c;
|
|
|
|
|
|
|
|
if (color < 0)
|
|
|
|
return;
|
|
|
|
c = color_rgb[color];
|
|
|
|
cairo_set_source_rgb(cr, (c >> 16) / 255.0, ((c >> 8) & 255) / 255.0,
|
|
|
|
(c & 255) / 255.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void paint(cairo_t *cr, int color, int fill_color)
|
|
|
|
{
|
|
|
|
if (fill_color != COLOR_NONE) {
|
|
|
|
set_color(cr, fill_color);
|
|
|
|
if (color == COLOR_NONE)
|
|
|
|
cairo_fill(cr);
|
|
|
|
else
|
|
|
|
cairo_fill_preserve(cr);
|
|
|
|
}
|
|
|
|
if (color != COLOR_NONE) {
|
|
|
|
set_color(cr, color);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----- General items ----------------------------------------------------- */
|
|
|
|
|
|
|
|
|
2016-07-31 20:07:29 +03:00
|
|
|
static void cr_poly(void *ctx, int points, int x[points], int y[points],
|
2016-07-31 06:04:43 +03:00
|
|
|
int color, int fill_color, unsigned layer)
|
|
|
|
{
|
|
|
|
struct cairo_ctx *cc = ctx;
|
|
|
|
bool closed;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (points < 2)
|
|
|
|
return;
|
|
|
|
closed = x[0] == x[points - 1] && y[0] == y[points - 1];
|
|
|
|
|
|
|
|
cairo_new_path(cc->cr);
|
2016-08-01 05:53:14 +03:00
|
|
|
cairo_move_to(cc->cr, cx(cc, x[0]), cy(cc, y[0]));
|
2016-07-31 06:04:43 +03:00
|
|
|
|
|
|
|
for (i = 1; i != points - closed; i++)
|
2016-08-01 05:53:14 +03:00
|
|
|
cairo_line_to(cc->cr, cx(cc, x[i]), cy(cc, y[i]));
|
2016-07-31 06:04:43 +03:00
|
|
|
if (closed)
|
|
|
|
cairo_close_path(cc->cr);
|
|
|
|
|
|
|
|
paint(cc->cr, color, fill_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-31 20:07:29 +03:00
|
|
|
static void cr_circ(void *ctx, int x, int y, int r,
|
2016-07-31 06:04:43 +03:00
|
|
|
int color, int fill_color, unsigned layer)
|
|
|
|
{
|
|
|
|
struct cairo_ctx *cc = ctx;
|
|
|
|
|
|
|
|
cairo_new_path(cc->cr);
|
2016-08-01 05:53:14 +03:00
|
|
|
cairo_arc(cc->cr, cx(cc, x), cy(cc, y), cd(cc, r), 0, 2 * M_PI);
|
2016-07-31 06:04:43 +03:00
|
|
|
paint(cc->cr, color, fill_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-31 20:07:29 +03:00
|
|
|
static void cr_arc(void *ctx, int x, int y, int r, int sa, int ea,
|
2016-07-31 06:04:43 +03:00
|
|
|
int color, int fill_color, unsigned layer)
|
|
|
|
{
|
|
|
|
struct cairo_ctx *cc = ctx;
|
|
|
|
|
|
|
|
cairo_new_path(cc->cr);
|
2016-08-01 05:53:14 +03:00
|
|
|
cairo_arc(cc->cr, cx(cc, x), cy(cc, y), cd(cc, r),
|
2016-07-31 06:04:43 +03:00
|
|
|
-ea / 180.0 * M_PI, -sa / 180.0 * M_PI);
|
|
|
|
paint(cc->cr, color, fill_color);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-31 09:28:08 +03:00
|
|
|
#define TEXT_STRETCH 1.3
|
|
|
|
|
|
|
|
|
2016-07-31 20:07:29 +03:00
|
|
|
static void cr_text(void *ctx, int x, int y, const char *s, unsigned size,
|
2016-07-31 06:04:43 +03:00
|
|
|
enum text_align align, int rot, unsigned color, unsigned layer)
|
|
|
|
{
|
2016-07-31 09:17:10 +03:00
|
|
|
struct cairo_ctx *cc = ctx;
|
|
|
|
cairo_text_extents_t ext;
|
|
|
|
cairo_matrix_t m;
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
cairo_set_font_size(cc->cr, cd(cc, size) * TEXT_STRETCH);
|
2016-07-31 09:17:10 +03:00
|
|
|
cairo_text_extents(cc->cr, s, &ext);
|
|
|
|
|
|
|
|
set_color(cc->cr, color);
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
cairo_move_to(cc->cr, cx(cc, x), cy(cc, y));
|
2016-07-31 09:17:10 +03:00
|
|
|
|
|
|
|
cairo_get_matrix(cc->cr, &m);
|
|
|
|
cairo_rotate(cc->cr, -rot / 180.0 * M_PI);
|
|
|
|
|
|
|
|
switch (align) {
|
|
|
|
case text_min:
|
|
|
|
break;
|
|
|
|
case text_mid:
|
|
|
|
cairo_rel_move_to(cc->cr, -ext.width / 2.0, 0);
|
|
|
|
break;
|
|
|
|
case text_max:
|
|
|
|
cairo_rel_move_to(cc->cr, -ext.width, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_show_text(cc->cr, s);
|
|
|
|
cairo_set_matrix(cc->cr, &m);
|
2016-07-31 06:04:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-31 20:07:29 +03:00
|
|
|
static unsigned cr_text_width(void *ctx, const char *s, unsigned size)
|
2016-07-31 09:28:08 +03:00
|
|
|
{
|
|
|
|
struct cairo_ctx *cc = ctx;
|
|
|
|
cairo_text_extents_t ext;
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
cairo_set_font_size(cc->cr, cx(cc, size) * TEXT_STRETCH);
|
2016-07-31 09:28:08 +03:00
|
|
|
cairo_text_extents(cc->cr, s, &ext);
|
2016-08-01 05:53:14 +03:00
|
|
|
return xc(cc, ext.width);
|
2016-07-31 09:28:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-31 06:04:43 +03:00
|
|
|
/* ----- Initializatio and termination ------------------------------------- */
|
|
|
|
|
|
|
|
|
2016-08-01 05:07:05 +03:00
|
|
|
static const struct gfx_ops real_cairo_ops = {
|
|
|
|
.name = "cairo",
|
|
|
|
// .line = cr_line, @@@ later
|
|
|
|
.poly = cr_poly,
|
|
|
|
.circ = cr_circ,
|
|
|
|
.arc = cr_arc,
|
|
|
|
.text = cr_text,
|
|
|
|
.text_width = cr_text_width,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-08-01 02:46:45 +03:00
|
|
|
static void *cr_init(int argc, char *const *argv)
|
2016-07-31 06:04:43 +03:00
|
|
|
{
|
|
|
|
struct cairo_ctx *cc;
|
|
|
|
|
|
|
|
cc = alloc_type(struct cairo_ctx);
|
2016-08-01 05:53:14 +03:00
|
|
|
cc->xo = cc->yo = 0;
|
|
|
|
cc->scale = 5;
|
2016-08-01 05:07:05 +03:00
|
|
|
layer_init(&cc->layer, &real_cairo_ops, cc);
|
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
/* cr_text_width needs *something* to work with */
|
2016-07-31 09:17:10 +03:00
|
|
|
|
2016-08-01 05:53:14 +03:00
|
|
|
cc->s = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 16, 16);
|
|
|
|
cc->cr = cairo_create(cc->s);
|
2016-07-31 06:04:43 +03:00
|
|
|
|
|
|
|
return cc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-31 20:07:29 +03:00
|
|
|
static void cr_end(void *ctx)
|
2016-07-31 06:04:43 +03:00
|
|
|
{
|
|
|
|
struct cairo_ctx *cc = ctx;
|
2016-08-01 05:53:14 +03:00
|
|
|
int x, y, w, h;
|
|
|
|
|
|
|
|
cairo_surface_destroy(cc->s);
|
|
|
|
cairo_destroy(cc->cr);
|
|
|
|
|
|
|
|
layer_bbox(&cc->layer, &x, &y, &w, &h);
|
|
|
|
|
|
|
|
// fprintf(stderr, "%dx%d%+d%+d\n", w, h, x, y);
|
|
|
|
cc->xo = -cd(cc, x);
|
|
|
|
cc->yo = -cd(cc, y);
|
|
|
|
w = cd(cc, w);
|
|
|
|
h = cd(cc, h);
|
|
|
|
// fprintf(stderr, "%dx%d%+d%+d\n", w, h, x, y);
|
|
|
|
|
|
|
|
cc->s = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
|
|
|
|
cc->cr = cairo_create(cc->s);
|
|
|
|
|
|
|
|
set_color(cc->cr, COLOR_WHITE);
|
|
|
|
cairo_paint(cc->cr);
|
|
|
|
|
|
|
|
cairo_select_font_face(cc->cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
|
|
|
|
CAIRO_FONT_WEIGHT_BOLD);
|
|
|
|
cairo_set_line_width(cc->cr, 3);
|
2016-07-31 06:04:43 +03:00
|
|
|
|
2016-08-01 05:07:05 +03:00
|
|
|
layer_replay(&cc->layer);
|
|
|
|
layer_destroy(&cc->layer);
|
|
|
|
|
2016-07-31 06:04:43 +03:00
|
|
|
cairo_surface_write_to_png(cc->s, "test.png");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----- Operations -------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
const struct gfx_ops cairo_ops = {
|
2016-08-01 03:52:35 +03:00
|
|
|
.name = "cairo",
|
2016-07-31 06:04:43 +03:00
|
|
|
// .line = cr_line, @@@ later
|
2016-08-01 05:07:05 +03:00
|
|
|
.poly = layer_poly,
|
|
|
|
.circ = layer_circ,
|
|
|
|
.arc = layer_arc,
|
|
|
|
.text = layer_text,
|
2016-07-31 09:28:08 +03:00
|
|
|
.text_width = cr_text_width,
|
|
|
|
.init = cr_init,
|
|
|
|
.end = cr_end,
|
2016-07-31 06:04:43 +03:00
|
|
|
};
|