[cairo-commit] [cairo-www] 5 commits - src/tutorial src/tutorial.mdwn

Carl Worth cworth at freedesktop.org
Thu Sep 20 14:49:08 PDT 2007


 src/tutorial.mdwn      |    8 
 src/tutorial/diagram.c |  464 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/tutorial/draw.c    |  375 +++++++++++++++++++++++++++++++++++++++
 src/tutorial/mask.c    |    4 
 4 files changed, 847 insertions(+), 4 deletions(-)

New commits:
commit 2aee5f70e29e3d701b353c558d343533fcc72bb7
Author: Nis Martensen <nis.martensen at web.de>
Date:   Sat Sep 15 10:49:38 2007 +0200

    Make the gradient code match the image

diff --git a/src/tutorial.mdwn b/src/tutorial.mdwn
index 96eb766..dd98d9f 100644
--- a/src/tutorial.mdwn
+++ b/src/tutorial.mdwn
@@ -246,9 +246,9 @@ pattern or surface is transparent, nothing is transferred.
 	cairo_pattern_add_color_stop_rgb (linpat, 0, 0, 0.3, 0.8);
 	cairo_pattern_add_color_stop_rgb (linpat, 1, 0, 0.8, 0.3);
 
-	radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.5);
+	radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.6);
 	cairo_pattern_add_color_stop_rgba (radpat, 0, 0, 0, 0, 1);
-	cairo_pattern_add_color_stop_rgba (radpat, 0.5, 0, 0, 0, 0);
+	cairo_pattern_add_color_stop_rgba (radpat, 1, 0, 0, 0, 0);
 
 	cairo_set_source (cr, linpat);
 	cairo_mask (cr, radpat);
diff --git a/src/tutorial/diagram.c b/src/tutorial/diagram.c
index c9cb004..a9432e7 100644
--- a/src/tutorial/diagram.c
+++ b/src/tutorial/diagram.c
@@ -432,9 +432,9 @@ void mask_draw_mask (cairo_t *cr)
 {
 	cairo_pattern_t *radialinv;
 
-	radialinv = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.5);
+	radialinv = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.6);
 	cairo_pattern_add_color_stop_rgba (radialinv, 0, 0, 0, 0, 0);
-	cairo_pattern_add_color_stop_rgba (radialinv, 0.5, 0, 0, 0, 1);
+	cairo_pattern_add_color_stop_rgba (radialinv, 1, 0, 0, 0, 1);
 
 	cairo_save (cr);
 	cairo_rectangle (cr, 0, 0, 1, 1);
@@ -450,9 +450,9 @@ void mask_draw_dest (cairo_t *cr)
 	cairo_pattern_add_color_stop_rgb (linpat, 0, 0, 0.3, 0.8);
 	cairo_pattern_add_color_stop_rgb (linpat, 1, 0, 0.8, 0.3);
 
-	radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.5);
+	radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.6);
 	cairo_pattern_add_color_stop_rgba (radpat, 0, 0, 0, 0, 1);
-	cairo_pattern_add_color_stop_rgba (radpat, 0.5, 0, 0, 0, 0);
+	cairo_pattern_add_color_stop_rgba (radpat, 1, 0, 0, 0, 0);
 
 	diagram_draw_dest (cr);
 	cairo_save (cr);
diff --git a/src/tutorial/mask.c b/src/tutorial/mask.c
index 30a8ff8..2a9e152 100644
--- a/src/tutorial/mask.c
+++ b/src/tutorial/mask.c
@@ -17,9 +17,9 @@ main (int argc, char *argv[])
 	cairo_pattern_add_color_stop_rgb (linpat, 0, 0, 0.3, 0.8);
 	cairo_pattern_add_color_stop_rgb (linpat, 1, 0, 0.8, 0.3);
 
-	radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.5);
+	radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.6);
 	cairo_pattern_add_color_stop_rgba (radpat, 0, 0, 0, 0, 1);
-	cairo_pattern_add_color_stop_rgba (radpat, 0.5, 0, 0, 0, 0);
+	cairo_pattern_add_color_stop_rgba (radpat, 1, 0, 0, 0, 0);
 
 	cairo_set_source (cr, linpat);
 	cairo_pattern_destroy (linpat);
commit c990695f0e127356a24e29da32a191eee903e5cf
Author: Nis Martensen <nis.martensen at web.de>
Date:   Fri Aug 24 22:58:14 2007 +0200

    add a link to the drawing code

diff --git a/src/tutorial.mdwn b/src/tutorial.mdwn
index e2ebb0b..96eb766 100644
--- a/src/tutorial.mdwn
+++ b/src/tutorial.mdwn
@@ -608,7 +608,8 @@ width.
 
 This wraps up the tutorial. It doesn't cover all functions in cairo, so
 for some "advanced" lesser-used features, you'll need to look elsewhere.
-The code behind the examples (<a href="diagram.c">layer diagrams</a>)
+The code behind the examples (<a href="diagram.c">layer diagrams</a>,
+<a href="draw.c">drawing illustrations</a>)
 uses a handful of techniques that aren't described within, so analyzing
 them may be a good first step.
 Other [[examples]] on cairographics.org lead in different directions. As
commit 38920dd37488d7445a56d3152fa76094f2d8d158
Author: Nis Martensen <nis.martensen at web.de>
Date:   Fri Aug 24 22:56:11 2007 +0200

    tutorial: add programm to generate the drawing diagrams

diff --git a/src/tutorial/draw.c b/src/tutorial/draw.c
new file mode 100644
index 0000000..4452254
--- /dev/null
+++ b/src/tutorial/draw.c
@@ -0,0 +1,375 @@
+/*
+ * draw.c draws the images in the "Drawing with cairo" section as part
+ * of the the cairo tutorial
+ * Copyright (C) 2007  Nis Martensen
+ * Derived from draw.py
+ * <http://www.tortall.net/mu/wiki/CairoTutorial/draw.py?raw>
+ * Copyright (C) 2006-2007 Michael Urman
+ *
+ * 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.
+ *
+ * This program 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <string.h>
+#include <math.h>
+#include <cairo.h>
+#include <cairo-svg.h>
+
+void diagram (char *name);
+void draw_diagram (char *name, cairo_t *cr);
+void draw_setsourcergba (cairo_t *cr);
+void draw_setsourcegradient (cairo_t *cr);
+void path_diagram (cairo_t *cr);
+void draw_path_curveto_hints (cairo_t *cr);
+void draw_path_moveto (cairo_t *cr);
+void draw_path_lineto (cairo_t *cr);
+void draw_path_arcto (cairo_t *cr);
+void draw_path_curveto (cairo_t *cr);
+void draw_path_close (cairo_t *cr);
+void draw_textextents (cairo_t *cr);
+
+int main ()
+{
+	diagram ("setsourcergba");
+	diagram ("setsourcegradient");
+	diagram ("path-moveto");
+	diagram ("path-lineto");
+	diagram ("path-arcto");
+	diagram ("path-curveto");
+	diagram ("path-close");
+	diagram ("textextents");
+
+	return 0;
+}
+
+void diagram (char *name)
+{
+	cairo_surface_t *surf;
+	cairo_t *cr;
+
+	double width=120, height=120;
+	double ux=2, uy=2;
+
+	char svg_filename[50];
+	char png_filename[50];
+	strcpy (svg_filename, name);
+	strcpy (png_filename, name);
+	strcat (svg_filename, ".svg");
+	strcat (png_filename, ".png");
+
+	surf = cairo_svg_surface_create (svg_filename, width, height);
+	cr = cairo_create (surf);
+
+	cairo_scale (cr, width, height);
+	cairo_set_line_width (cr, 0.01);
+
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_set_source_rgb (cr, 1, 1, 1);
+	cairo_fill (cr);
+
+	draw_diagram (name, cr);
+
+	cairo_device_to_user_distance (cr, &ux, &uy);
+	if (ux < uy)
+		ux = uy;
+	cairo_set_line_width (cr, ux);
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_stroke (cr);
+
+	/* write output and clean up */
+	cairo_surface_write_to_png (surf, png_filename);
+	cairo_destroy (cr);
+	cairo_surface_destroy (surf);
+}
+
+void draw_diagram (char *name, cairo_t *cr)
+{
+	if (strcmp(name, "setsourcergba") == 0) {
+		draw_setsourcergba (cr);
+	} else if (strcmp(name, "setsourcegradient") == 0) {
+		draw_setsourcegradient (cr);
+	} else if (strcmp(name, "path-moveto") == 0) {
+		draw_path_moveto (cr);
+	} else if (strcmp(name, "path-lineto") == 0) {
+		draw_path_lineto (cr);
+	} else if (strcmp(name, "path-arcto") == 0) {
+		draw_path_arcto (cr);
+	} else if (strcmp(name, "path-curveto") == 0) {
+		draw_path_curveto_hints (cr);
+		draw_path_curveto (cr);
+	} else if (strcmp(name, "path-close") == 0) {
+		draw_path_close (cr);
+	} else if (strcmp(name, "textextents") == 0) {
+		draw_textextents (cr);
+	}
+
+	if (strncmp(name, "path-", 5) == 0)
+		path_diagram (cr);
+}
+
+void draw_setsourcergba (cairo_t *cr)
+{
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_move_to (cr, 0, 0);
+	cairo_line_to (cr, 1, 1);
+	cairo_move_to (cr, 1, 0);
+	cairo_line_to (cr, 0, 1);
+	cairo_set_line_width (cr, 0.2);
+	cairo_stroke (cr);
+
+	cairo_rectangle (cr, 0, 0, 0.5, 0.5);
+	cairo_set_source_rgba (cr, 1, 0, 0, 0.80);
+	cairo_fill (cr);
+
+	cairo_rectangle (cr, 0, 0.5, 0.5, 0.5);
+	cairo_set_source_rgba (cr, 0, 1, 0, 0.60);
+	cairo_fill (cr);
+
+	cairo_rectangle (cr, 0.5, 0, 0.5, 0.5);
+	cairo_set_source_rgba (cr, 0, 0, 1, 0.40);
+	cairo_fill (cr);
+}
+
+void draw_setsourcegradient (cairo_t *cr)
+{
+	int i, j;
+	cairo_pattern_t *radpat, *linpat;
+
+	radpat = cairo_pattern_create_radial (0.25, 0.25, 0.1, 0.5, 0.5, 0.5);
+	cairo_pattern_add_color_stop_rgb (radpat, 0, 1.0, 0.8, 0.8);
+	cairo_pattern_add_color_stop_rgb (radpat, 1, 0.9, 0.0, 0.0);
+
+	for (i = 1; i < 10; i++)
+		for (j = 1; j < 10; j++)
+			cairo_rectangle (cr, i / 10.0 - 0.04, j / 10.0 - 0.04,
+					 0.08, 0.08);
+	cairo_set_source (cr, radpat);
+	cairo_fill (cr);
+
+	linpat = cairo_pattern_create_linear (0.25, 0.35, 0.75, 0.65);
+	cairo_pattern_add_color_stop_rgba (linpat, 0.00, 1, 1, 1, 0);
+	cairo_pattern_add_color_stop_rgba (linpat, 0.25, 0, 1, 0, 0.5);
+	cairo_pattern_add_color_stop_rgba (linpat, 0.50, 1, 1, 1, 0);
+	cairo_pattern_add_color_stop_rgba (linpat, 0.75, 0, 0, 1, 0.5);
+	cairo_pattern_add_color_stop_rgba (linpat, 1.00, 1, 1, 1, 0);
+
+	cairo_rectangle (cr, 0.0, 0.0, 1, 1);
+	cairo_set_source (cr, linpat);
+	cairo_fill (cr);
+}
+
+void path_diagram (cairo_t *cr)
+{
+	cairo_path_t *path;
+	cairo_path_data_t *data;
+	double x, y, px = 3, py = 3;
+
+	path = cairo_copy_path_flat (cr);
+
+	cairo_device_to_user_distance (cr, &px, &py);
+	if (px < py)
+		px = py;
+	cairo_set_line_width (cr, px);
+	cairo_set_source_rgb (cr, 0, 0.6, 0);
+	cairo_stroke (cr);
+
+	if (path->num_data > 1) {
+		/*
+		 * Draw markers at the first and the last point of the
+		 * path, but only if the path is not closed.
+		 *
+		 * If the last path manipulation was a cairo_close(),
+		 * then we can detect this at the end of the path->data
+		 * array. The CLOSE_PATH element will be followed by a
+		 * MOVE_TO element (since cairo 1.2.4), so we need to
+		 * check position path->num_data - 3.
+		 *
+		 * More details can be found here:
+		 * <http://cairographics.org/manual/cairo-Paths.html#cairo-close-path>
+		 * <http://cairographics.org/manual/cairo-Paths.html#cairo-path-data-t>
+		 */
+		if (path->data[path->num_data-3].header.type != CAIRO_PATH_CLOSE_PATH) {
+			/* Get the first point in the path */
+			data = &path->data[0];
+			x = data[1].point.x;
+			y = data[1].point.y;
+
+			px = 5; py = 5;
+			cairo_device_to_user_distance (cr, &px, &py);
+			if (px < py)
+				px = py;
+
+			cairo_arc (cr, x, y, px, 0, 2*M_PI);
+			cairo_set_source_rgba (cr, 0.0, 0.6, 0.0, 0.5);
+			cairo_fill(cr);
+
+			/*
+			 * Because cairo_copy_path_flat() was used to
+			 * retrieve this path, there is no CURVE_TO
+			 * element, so the elements all have a length of
+			 * 2. The index of the last element must be
+			 * path->num_data - 2.
+			 */
+			data = &path->data[path->num_data-2];
+			x = data[1].point.x;
+			y = data[1].point.y;
+			cairo_arc (cr, x, y, px, 0, 2*M_PI);
+			cairo_set_source_rgba (cr, 0.0, 0.0, 0.75, 0.5);
+			cairo_fill (cr);
+		}
+	}
+
+	cairo_path_destroy (path);
+}
+
+void draw_path_curveto_hints (cairo_t *cr)
+{
+	double px = 3, py = 3;
+	cairo_save (cr);
+	cairo_device_to_user_distance (cr, &px, &py);
+	if (px < py)
+		px = py;
+	cairo_set_source_rgba (cr, 0.5, 0, 0, 0.5);
+
+	cairo_new_sub_path (cr);
+	cairo_arc (cr, 0.5, 0.625, px, 0, 2*M_PI);
+	cairo_fill (cr);
+	cairo_arc (cr, 0.5, 0.875, px, 0, 2*M_PI);
+	cairo_fill (cr);
+
+	px = 2; py = 2;
+	cairo_device_to_user_distance (cr, &px, &py);
+	if (px < py)
+		px = py;
+	cairo_set_line_width (cr, px);
+	cairo_set_source_rgba (cr, 0.5, 0, 0, 0.25);
+
+	cairo_move_to (cr, 0.25, 0.75);
+	cairo_rel_line_to (cr, 0.25, 0.125);
+	cairo_stroke (cr);
+
+	cairo_move_to (cr, 0.75, 0.75);
+	cairo_rel_line_to (cr, -0.25, -0.125);
+	cairo_stroke (cr);
+
+	cairo_restore (cr);
+}
+
+void draw_path_moveto (cairo_t *cr)
+{
+	cairo_set_line_width (cr, 0.1);
+	cairo_set_source_rgb (cr, 0, 0, 0);
+
+	cairo_move_to (cr, 0.25, 0.25);
+}
+
+void draw_path_lineto (cairo_t *cr)
+{
+	draw_path_moveto (cr);
+
+	cairo_line_to (cr, 0.5, 0.375);
+	cairo_rel_line_to (cr, 0.25, -0.125);
+}
+
+void draw_path_arcto (cairo_t *cr)
+{
+	draw_path_lineto (cr);
+
+	cairo_arc (cr, 0.5, 0.5, 0.25 * sqrt(2), -0.25 * M_PI, 0.25 * M_PI);
+}
+
+void draw_path_curveto (cairo_t *cr)
+{
+	draw_path_arcto (cr);
+
+	cairo_rel_curve_to (cr, -0.25, -0.125, -0.25, 0.125, -0.5, 0);
+}
+
+void draw_path_close (cairo_t *cr)
+{
+	draw_path_curveto (cr);
+
+	cairo_close_path (cr);
+}
+
+void draw_textextents (cairo_t *cr)
+{
+	double x, y, px, ux=1, uy=1, dashlength;
+	char text[]="joy";
+	cairo_font_extents_t fe;
+	cairo_text_extents_t te;
+
+	cairo_set_font_size (cr, 0.5);
+
+	/* Drawing code goes here */
+	cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+	cairo_select_font_face (cr, "Georgia",
+			CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+	cairo_font_extents (cr, &fe);
+
+	cairo_device_to_user_distance (cr, &ux, &uy);
+	if (ux > uy)
+		px = ux;
+	else
+		px = uy;
+	cairo_font_extents (cr, &fe);
+	cairo_text_extents (cr, text, &te);
+	x = 0.5 - te.x_bearing - te.width / 2;
+	y = 0.5 - fe.descent + fe.height / 2;
+
+	/* baseline, descent, ascent, height */
+	cairo_set_line_width (cr, 4*px);
+	dashlength = 9*px;
+	cairo_set_dash (cr, &dashlength, 1, 0);
+	cairo_set_source_rgba (cr, 0, 0.6, 0, 0.5);
+	cairo_move_to (cr, x + te.x_bearing, y);
+	cairo_rel_line_to (cr, te.width, 0);
+	cairo_move_to (cr, x + te.x_bearing, y + fe.descent);
+	cairo_rel_line_to (cr, te.width, 0);
+	cairo_move_to (cr, x + te.x_bearing, y - fe.ascent);
+	cairo_rel_line_to (cr, te.width, 0);
+	cairo_move_to (cr, x + te.x_bearing, y - fe.height);
+	cairo_rel_line_to (cr, te.width, 0);
+	cairo_stroke (cr);
+
+	/* extents: width & height */
+	cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
+	cairo_set_line_width (cr, px);
+	dashlength = 3*px;
+	cairo_set_dash (cr, &dashlength, 1, 0);
+	cairo_rectangle (cr, x + te.x_bearing, y + te.y_bearing, te.width, te.height);
+	cairo_stroke (cr);
+
+	/* text */
+	cairo_move_to (cr, x, y);
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_show_text (cr, text);
+
+	/* bearing */
+	cairo_set_dash (cr, NULL, 0, 0);
+	cairo_set_line_width (cr, 2 * px);
+	cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
+	cairo_move_to (cr, x, y);
+	cairo_rel_line_to (cr, te.x_bearing, te.y_bearing);
+	cairo_stroke (cr);
+
+	/* text's advance */
+	cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
+	cairo_arc (cr, x + te.x_advance, y + te.y_advance, 5 * px, 0, 2 * M_PI);
+	cairo_fill (cr);
+
+	/* reference point */
+	cairo_arc (cr, x, y, 5 * px, 0, 2 * M_PI);
+	cairo_set_source_rgba (cr, 0.75, 0, 0, 0.5);
+	cairo_fill (cr);
+}
commit e8a739007e8c6d3598f05e130fb0654a6d51f434
Author: Nis Martensen <nis.martensen at web.de>
Date:   Tue Aug 21 19:09:27 2007 +0200

    add a link to the diagram code

diff --git a/src/tutorial.mdwn b/src/tutorial.mdwn
index d44a1b9..e2ebb0b 100644
--- a/src/tutorial.mdwn
+++ b/src/tutorial.mdwn
@@ -608,6 +608,9 @@ width.
 
 This wraps up the tutorial. It doesn't cover all functions in cairo, so
 for some "advanced" lesser-used features, you'll need to look elsewhere.
+The code behind the examples (<a href="diagram.c">layer diagrams</a>)
+uses a handful of techniques that aren't described within, so analyzing
+them may be a good first step.
 Other [[examples]] on cairographics.org lead in different directions. As
 with everything, there's a large gap between knowing the rules of the
 tool, and being able to use it well. The final section of this document
commit 37ebc719a5bd9acc323d4f8a6f3467e7e8425c77
Author: Nis Martensen <nis.martensen at web.de>
Date:   Tue Aug 21 11:22:24 2007 +0200

    tutorial: add program to generate the layer diagrams

diff --git a/src/tutorial/diagram.c b/src/tutorial/diagram.c
new file mode 100644
index 0000000..c9cb004
--- /dev/null
+++ b/src/tutorial/diagram.c
@@ -0,0 +1,464 @@
+/*
+ * diagram.c draws the layer diagrams as part of the the cairo tutorial
+ * Copyright (C) 2007  Nis Martensen
+ * Derived from diagram.py
+ * <http://www.tortall.net/mu/wiki/CairoTutorial/diagram.py?raw>
+ * Copyright (C) 2006-2007 Michael Urman
+ *
+ * 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.
+ *
+ * This program 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
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <string.h>
+#include <cairo.h>
+#include <cairo-svg.h>
+
+void diagram (char *name, double *alpha);
+void draw_source (char *name, cairo_t *cr);
+void draw_mask (char *name, cairo_t *cr);
+void draw_dest (char *name, cairo_t *cr);
+void diagram_draw_source (cairo_t *cr);
+void diagram_draw_mask (cairo_t *cr);
+void diagram_draw_mask_pattern (cairo_t *cr, cairo_pattern_t *pat);
+void diagram_draw_dest (cairo_t *cr);
+void stroke_draw_mask (cairo_t *cr);
+void stroke_draw_dest (cairo_t *cr);
+void fill_draw_mask (cairo_t *cr);
+void fill_draw_dest (cairo_t *cr);
+void showtext_draw_mask (cairo_t *cr);
+void showtext_draw_dest (cairo_t *cr);
+void paint_draw_source (cairo_t *cr);
+void paint_draw_dest (cairo_t *cr);
+void mask_draw_source (cairo_t *cr);
+void mask_draw_mask (cairo_t *cr);
+void mask_draw_dest (cairo_t *cr);
+
+int main ()
+{
+	double alpha[3];
+
+	alpha[0]=1.0;  alpha[1]=0.15;  alpha[2]=0.15;
+	diagram ("destination", alpha);
+
+	alpha[0]=0.15;  alpha[1]=1.0;  alpha[2]=0.15;
+	diagram ("the-mask", alpha);
+
+	alpha[0]=0.15;  alpha[1]=0.15;  alpha[2]=1.0;
+	diagram ("source", alpha);
+
+	alpha[0]=1.0;  alpha[1]=0.8;  alpha[2]=0.4;
+	diagram ("stroke", alpha);
+
+	alpha[0]=1.0;  alpha[1]=0.8;  alpha[2]=0.4;
+	diagram ("fill", alpha);
+
+	alpha[0]=1.0;  alpha[1]=0.8;  alpha[2]=0.4;
+	diagram ("showtext", alpha);
+
+	alpha[0]=1.0;  alpha[1]=0.8;  alpha[2]=0.4;
+	diagram ("paint", alpha);
+
+	alpha[0]=1.0;  alpha[1]=0.8;  alpha[2]=0.4;
+	diagram ("mask", alpha);
+
+	return 0;
+}
+
+void diagram (char *name, double *alpha)
+{
+	cairo_surface_t *surf;
+	cairo_t *cr;
+	cairo_matrix_t mat;
+
+	double width=160, height=120;
+	double ux=2, uy=2;
+
+	char svg_filename[50];
+	char png_filename[50];
+	strcpy (svg_filename, name);
+	strcpy (png_filename, name);
+	strcat (svg_filename, ".svg");
+	strcat (png_filename, ".png");
+
+	surf = cairo_svg_surface_create (svg_filename, width, height);
+	cr = cairo_create (surf);
+
+	/*
+	 * show layers separately on the right
+	 */
+	cairo_save (cr);
+	cairo_scale (cr, height/3, height/3);
+	cairo_translate (cr, 3*width/height-1, 0);
+	/* source */
+	cairo_save (cr);
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	draw_source (name, cr);
+	cairo_pop_group_to_source (cr);
+	cairo_paint (cr);
+	cairo_restore (cr);
+	/* mask */
+	cairo_translate (cr, 0, 1);
+	cairo_save (cr);
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	draw_mask (name, cr);
+	cairo_pop_group_to_source (cr);
+	cairo_paint (cr);
+	cairo_restore (cr);
+	/* destination */
+	cairo_translate (cr, 0, 1);
+	cairo_save (cr);
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	draw_dest (name, cr);
+	cairo_pop_group_to_source (cr);
+	cairo_paint (cr);
+	cairo_restore (cr);
+	cairo_restore (cr);
+
+	/* draw a border around the layers */
+	cairo_save (cr);
+	cairo_scale (cr, height/3, height/3);
+	cairo_translate (cr, 3*width/height-1, 0);
+	cairo_device_to_user_distance (cr, &ux, &uy);
+	if (ux < uy)
+		ux = uy;
+	cairo_set_line_width (cr, ux);
+	cairo_rectangle (cr, 0, 0, 1, 3);
+	cairo_clip_preserve (cr);
+	cairo_stroke (cr);
+	cairo_rectangle (cr, 0, 1, 1, 1);
+	cairo_stroke (cr);
+	cairo_restore (cr);
+
+	/*
+	 * layer diagram on the left
+	 */
+
+	/* destination layer */
+	cairo_save (cr);
+	cairo_scale (cr, width-height/3, height);
+	cairo_matrix_init (&mat, 0.6, 0, 1.0/3, 0.5, 0.02, 0.45);
+	cairo_transform (cr, &mat);
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	draw_dest (name, cr);
+	/* this layer gets a black border */
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	ux = 2; uy = 2;
+	cairo_device_to_user_distance (cr, &ux, &uy);
+	if (ux < uy)
+		ux = uy;
+	cairo_set_line_width (cr, ux);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_stroke (cr);
+	cairo_pop_group_to_source (cr);
+	cairo_paint_with_alpha (cr, alpha[0]);
+	cairo_restore (cr);
+
+	/* mask layer */
+	cairo_save (cr);
+	cairo_scale (cr, width-height/3, height);
+	cairo_matrix_init (&mat, 0.6, 0, 1.0/3, 0.5, 0.04, 0.25);
+	cairo_transform (cr, &mat);
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	draw_mask (name, cr);
+	cairo_pop_group_to_source (cr);
+	cairo_paint_with_alpha (cr, alpha[1]);
+	cairo_restore (cr);
+
+	/* source layer */
+	cairo_save (cr);
+	cairo_scale (cr, width-height/3, height);
+	cairo_matrix_init (&mat, 0.6, 0, 1.0/3, 0.5, 0.06, 0.05);
+	cairo_transform (cr, &mat);
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	draw_source (name, cr);
+	cairo_pop_group_to_source (cr);
+	cairo_paint_with_alpha (cr, alpha[2]);
+	cairo_restore (cr);
+
+	/* write output and clean up */
+	cairo_surface_write_to_png (surf, png_filename);
+	cairo_destroy (cr);
+	cairo_surface_destroy (surf);
+}
+
+void draw_source (char *name, cairo_t *cr)
+{
+	if (strcmp (name, "paint") == 0) {
+		paint_draw_source (cr);
+	} else if (strcmp (name, "mask") == 0) {
+		mask_draw_source (cr);
+	} else {
+		diagram_draw_source (cr);
+	}
+}
+
+void draw_mask (char *name, cairo_t *cr)
+{
+	if (strcmp (name, "stroke") == 0) {
+		stroke_draw_mask (cr);
+	} else if (strcmp (name, "fill") == 0) {
+		fill_draw_mask (cr);
+	} else if (strcmp (name, "showtext") == 0) {
+		showtext_draw_mask (cr);
+	} else if (strcmp (name, "paint") == 0) {
+	} else if (strcmp (name, "mask") == 0) {
+		mask_draw_mask (cr);
+	} else {
+		diagram_draw_mask (cr);
+	}
+}
+void draw_dest (char *name, cairo_t *cr)
+{
+	if (strcmp(name, "stroke") == 0) {
+		stroke_draw_dest (cr);
+	} else if (strcmp(name, "fill") == 0) {
+		fill_draw_dest (cr);
+	} else if (strcmp(name, "showtext") == 0) {
+		showtext_draw_dest (cr);
+	} else if (strcmp(name, "paint") == 0) {
+		paint_draw_dest (cr);
+	} else if (strcmp(name, "mask") == 0) {
+		mask_draw_dest (cr);
+	} else {
+		diagram_draw_dest (cr);
+	}
+}
+
+void diagram_draw_source (cairo_t *cr)
+{
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_fill (cr);
+}
+
+void diagram_draw_mask (cairo_t *cr)
+{
+	cairo_set_source_rgb (cr, 1, 0.9, 0.6);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_fill (cr);
+}
+
+void diagram_draw_mask_pattern (cairo_t *cr, cairo_pattern_t *pat)
+{
+	cairo_set_source_rgb (cr, 1, 0.9, 0.6);
+	cairo_mask (cr, pat);
+}
+
+void diagram_draw_dest (cairo_t *cr)
+{
+	cairo_set_source_rgb (cr, 1, 1, 1);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_fill (cr);
+}
+
+void stroke_draw_mask (cairo_t *cr)
+{
+	double px=1, py=1;
+	cairo_pattern_t *pat;
+
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_rectangle (cr, 0.20, 0.20, 0.6, 0.6);
+	cairo_rectangle (cr, 0.30, 0.30, 0.4, 0.4);
+	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+	cairo_fill (cr);
+	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+
+	pat = cairo_pop_group (cr);
+
+	diagram_draw_mask_pattern (cr, pat);
+
+	cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
+	cairo_set_source_rgb (cr, 0, 0.6, 0);
+
+	cairo_device_to_user_distance (cr, &px, &py);
+	if (px < py)
+		px = py;
+	cairo_set_line_width (cr, px);
+	cairo_stroke (cr);
+}
+
+void stroke_draw_dest (cairo_t *cr)
+{
+	diagram_draw_dest (cr);
+
+	cairo_set_line_width (cr, 0.1);
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
+	cairo_stroke (cr);
+}
+
+void fill_draw_mask (cairo_t *cr)
+{
+	double px=1, py=1;
+	cairo_pattern_t *pat;
+
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
+	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+	cairo_fill (cr);
+	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+	pat = cairo_pop_group (cr);
+
+	diagram_draw_mask_pattern (cr, pat);
+
+	cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
+	cairo_set_source_rgb (cr, 0, 0.6, 0);
+	cairo_device_to_user_distance (cr, &px, &py);
+	if (px < py)
+		px = py;
+	cairo_set_line_width (cr, px);
+	cairo_stroke (cr);
+}
+
+void fill_draw_dest (cairo_t *cr)
+{
+	diagram_draw_dest (cr);
+
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
+	cairo_fill (cr);
+}
+
+void showtext_draw_mask (cairo_t *cr)
+{
+	cairo_text_extents_t te;
+	double ux=1, uy=1;
+
+	/* yellow mask color */
+	cairo_set_source_rgb (cr, 1, 0.9, 0.6);
+
+	/* rectangle with an "a"-shaped hole */
+	cairo_select_font_face (cr, "Georgia",
+			CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+	cairo_set_font_size (cr, 1.2);
+	cairo_text_extents (cr, "a", &te);
+
+	cairo_push_group (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_move_to (cr, 0.5 - te.width / 2 - te.x_bearing,
+			0.5 - te.height / 2 - te.y_bearing);
+	cairo_text_path (cr, "a");
+	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+	cairo_fill (cr);
+	cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+	cairo_pop_group_to_source (cr);
+	cairo_paint (cr);
+
+	/* show the outline of the glyph with a green line */
+	cairo_move_to (cr, 0.5 - te.width / 2 - te.x_bearing,
+			0.5 - te.height / 2 - te.y_bearing);
+	cairo_set_source_rgb (cr, 0, 0.6, 0);
+
+	cairo_device_to_user_distance (cr, &ux, &uy);
+	if (ux < uy)
+		ux = uy;
+	cairo_set_line_width (cr, ux);
+
+	cairo_text_path (cr, "a");
+	cairo_stroke (cr);
+}
+
+void showtext_draw_dest (cairo_t *cr)
+{
+	cairo_text_extents_t te;
+
+	/* white background */
+	cairo_set_source_rgb (cr, 1, 1, 1);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_fill (cr);
+
+	/* black letter "a" */
+	cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+	cairo_select_font_face (cr, "Georgia",
+			CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+	cairo_set_font_size (cr, 1.2);
+	cairo_text_extents (cr, "a", &te);
+	cairo_move_to (cr, 0.5 - te.width / 2 - te.x_bearing,
+			0.5 - te.height / 2 - te.y_bearing);
+	cairo_show_text (cr, "a");
+}
+
+void paint_draw_source (cairo_t *cr)
+{
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_fill (cr);
+}
+
+void paint_draw_dest (cairo_t *cr)
+{
+	diagram_draw_dest (cr);
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_paint_with_alpha (cr, 0.5);
+}
+
+void mask_draw_source (cairo_t *cr)
+{
+	cairo_pattern_t *linpat;
+
+	linpat = cairo_pattern_create_linear (0, 0, 1, 1);
+	cairo_pattern_add_color_stop_rgb (linpat, 0, 0, 0.3, 0.8);
+	cairo_pattern_add_color_stop_rgb (linpat, 1, 0, 0.8, 0.3);
+
+	cairo_set_source (cr, linpat);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_fill (cr);
+}
+
+void mask_draw_mask (cairo_t *cr)
+{
+	cairo_pattern_t *radialinv;
+
+	radialinv = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.5);
+	cairo_pattern_add_color_stop_rgba (radialinv, 0, 0, 0, 0, 0);
+	cairo_pattern_add_color_stop_rgba (radialinv, 0.5, 0, 0, 0, 1);
+
+	cairo_save (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	diagram_draw_mask_pattern (cr, radialinv);
+	cairo_restore (cr);
+}
+
+void mask_draw_dest (cairo_t *cr)
+{
+	cairo_pattern_t *linpat, *radpat;
+	linpat = cairo_pattern_create_linear (0, 0, 1, 1);
+	cairo_pattern_add_color_stop_rgb (linpat, 0, 0, 0.3, 0.8);
+	cairo_pattern_add_color_stop_rgb (linpat, 1, 0, 0.8, 0.3);
+
+	radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.5);
+	cairo_pattern_add_color_stop_rgba (radpat, 0, 0, 0, 0, 1);
+	cairo_pattern_add_color_stop_rgba (radpat, 0.5, 0, 0, 0, 0);
+
+	diagram_draw_dest (cr);
+	cairo_save (cr);
+	cairo_rectangle (cr, 0, 0, 1, 1);
+	cairo_clip (cr);
+	cairo_set_source (cr, linpat);
+	cairo_mask (cr, radpat);
+	cairo_restore (cr);
+}


More information about the cairo-commit mailing list