/* $Id$ * * Copyright © 2004 Keith Packard * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is Keith Packard * * Contributor(s): * Keith Packard */ Environ::set("FREETYPE_PROPERTIES", "truetype:interpreter-version=35"); if (!Command::valid_name ((string[]) { "Cairo" })) Foreign::load ("libcairo-5c.so.0"); extend namespace Cairo { public typedef void (real x, real y) move_to_func_t; public typedef void (real x, real y) line_to_func_t; public typedef void (real x1, real y1, real x2, real y2, real x3, real y3) curve_to_func_t; public typedef void () close_path_func_t; public typedef struct { real hue, saturation, value; } hsv_color_t; public real width (cairo_t cr) = Surface::width (get_target (cr)); public real height (cairo_t cr) = Surface::height (get_target (cr)); public file open_event (cairo_t cr) = Surface::open_event (get_target (cr)); public cairo_t new (int args...) { int w = dim(args) > 0 ? args[0] : 0; int h = dim(args) > 1 ? args[1] : 0; string name = (dim (argv) > 0) ? argv[0] : "nickle"; cairo_t cr = create (Surface::create_window (name, w, h)); set_source_rgba (cr, 1, 1, 1, 1); paint (cr); set_source_rgba (cr, 0, 0, 0, 1); return cr; } public cairo_t new_window (string name, int args...) { int w = dim(args) > 0 ? args[0] : 0; int h = dim(args) > 1 ? args[1] : 0; surface_t surface = Surface::create_window (name, w, h); cairo_t cr = create (surface); set_source_rgba (cr, 1, 1, 1, 1); paint (cr); set_source_rgba (cr, 0, 0, 0, 1); return cr; } public cairo_t new_image (int width, int height) { surface_t surface = Image::surface_create (Image::format_t.ARGB, width, height); cairo_t cr = create (surface); set_source_rgba (cr, 0, 0, 0, 0); set_operator (cr, operator_t.SOURCE); paint (cr); set_operator (cr, operator_t.OVER); set_source_rgba (cr, 0, 0, 0, 1); return cr; } public void write_to_png (cairo_t cr, string filename) { surface_t surface = get_target (cr); Surface::write_to_png (surface, filename); } public cairo_t new_pdf (string filename, real width, real height) { surface_t surface = Pdf::surface_create (filename, width, height); cairo_t cr = create (surface); set_source_rgba (cr, 1, 1, 1, 1); paint (cr); set_source_rgba (cr, 0, 0, 0, 1); return cr; } public cairo_t new_svg (string filename, real width, real height) { surface_t surface = Svg::surface_create (filename, width, height); cairo_t cr = create (surface); return cr; } public cairo_t dup (cairo_t cr) { return create (get_target (cr)); } real[3] to_hsv(real r, real g, real b) { real minimum = min (r, g, b); real maximum = max (r, g, b); real v = maximum; real s = (maximum == 0) ? 0 : (maximum - minimum) / maximum; real h = 0; if (s != 0) { switch (maximum) { case r: h = (g - b) / (maximum - minimum); break; case g: h = 2.0 + (b - r) / (maximum - minimum); break; case b: h = 4.0 + (r - g) / (maximum - minimum); break; } h = h / 6; } return (real[3]) { h, s, v }; } /* convert hsv to rgb */ real[3] from_hsv(real h, real s, real v) { if (v == 0.0) return (real[3]) { 0 ... }; else if (s == 0.0) { return (real[3]) { v ... }; } else { real h6 = (h * 6) % 6; int i = floor (h6); real f = h6 - i; real p = v * (1 - s); real q = v * (1 - (s * f)); real t = v * (1 - (s * (1 - f))); switch(i) { default:return (real[3]) { v, t, p }; case 1: return (real[3]) { q, v, p }; case 2: return (real[3]) { p, v, t }; case 3: return (real[3]) { p, q, v }; case 4: return (real[3]) { t, p, v }; case 5: return (real[3]) { v, p, q }; } } } public rgb_color_t hsv_to_rgb (hsv_color_t hsv) { real[3] rgb = from_hsv (hsv.hue, hsv.saturation, hsv.value); return (rgb_color_t) { red = rgb[0], green = rgb[1], blue = rgb[2] }; } public hsv_color_t rgb_to_hsv (rgb_color_t rgb) { real[3] hsv = to_hsv (rgb.red, rgb.green, rgb.blue); return (hsv_color_t) { hue = hsv[0], saturation = hsv[1], value = hsv[2] }; } public void set_source_hsv (cairo_t cr, real h, real s, real v) /* * Set color using HSV specification * H: hue 0 = red, 0.{3} = green, 0.{6} = blue * S: satuation 0..1 * V: value 0..1 */ { set_source_rgb (cr, from_hsv (h, s, v) ...); } public namespace Matrix { matrix_t multiply_scalar (matrix_t a, real scalar) = (matrix_t) { xx = a.xx * scalar, yx = a.yx * scalar, xy = a.xy * scalar, yy = a.yy * scalar, x0 = a.x0 * scalar, y0 = a.y0 * scalar }; public matrix_t identity () = (matrix_t) { xx = 1, yx = 0, xy = 0, yy = 1, x0 = 0, y0 = 0 }; public real determinant (matrix_t m) = m.xx * m.yy - m.yx * m.xy; /* This function isn't a correct adjoint in that the implicit 1 in the homogeneous result should actually be ad-bc instead. But, since this adjoint is only used in the computation of the inverse, which divides by det (A)=ad-bc anyway, everything works out in the end. */ matrix_t adjoint (matrix_t m) = (matrix_t) { xx = m.yy, yx = -m.xy, xy = -m.yx, yy = m.xx, x0 = m.yx * m.y0 - m.yy * m.x0, y0 = m.xy * m.x0 - m.xx * m.y0 }; /* inv (A) = 1/det (A) * adj (A) */ public matrix_t invert (matrix_t a) = multiply_scalar (adjoint (a), 1 / determinant (a)); public matrix_t multiply (matrix_t a, matrix_t b) = (matrix_t) { xx = a.xx * b.xx + a.yx * b.xy, yx = a.xx * b.yx + a.yx * b.yy, xy = a.xy * b.xx + a.yy * b.xy, yy = a.xy * b.yx + a.yy * b.yy, x0 = a.x0 * b.xx + a.y0 * b.xy + b.x0, y0 = a.x0 * b.yx + a.y0 * b.yy + b.y0 }; public matrix_t translate (matrix_t m, real tx, real ty) = multiply ((matrix_t) { xx = 1, yx = 0, xy = 0, yy = 1, x0 = tx, y0 = ty }, m); public matrix_t scale (matrix_t m, real sx, real sy) = multiply ((matrix_t) { xx = sx, yx = 0, xy = 0, yy = sy, x0 = 0, y0 = 0 }, m); public matrix_t rotate (matrix_t m, real a) = multiply ((matrix_t) { xx = (real c = cos(a)), yx = (real s = sin(a)), xy = -s, yy = c, x0 = 0, y0 = 0 }, m); public point_t point (matrix_t m, point_t p) = (point_t) { x = m.xx * p.x + m.yx * p.y + m.x0, y = m.xy * p.x + m.yy * p.y + m.y0 }; public point_t distance (matrix_t m, point_t p) = (point_t) { x = m.xx * p.x + m.yx * p.y, y = m.xy * p.x + m.yy * p.y }; } }