summaryrefslogtreecommitdiffstats
path: root/app/text/gimptext-vectors.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/text/gimptext-vectors.c')
-rw-r--r--app/text/gimptext-vectors.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/app/text/gimptext-vectors.c b/app/text/gimptext-vectors.c
new file mode 100644
index 0000000..3a6901e
--- /dev/null
+++ b/app/text/gimptext-vectors.c
@@ -0,0 +1,255 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * GimpText-vectors
+ * Copyright (C) 2003 Sven Neumann <sven@gimp.org>
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <pango/pangocairo.h>
+#include <gegl.h>
+
+#include "text-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpimage.h"
+
+#include "vectors/gimpbezierstroke.h"
+#include "vectors/gimpvectors.h"
+#include "vectors/gimpanchor.h"
+
+#include "gimptext.h"
+#include "gimptext-vectors.h"
+#include "gimptextlayout.h"
+#include "gimptextlayout-render.h"
+
+
+typedef struct
+{
+ GimpVectors *vectors;
+ GimpStroke *stroke;
+ GimpAnchor *anchor;
+} RenderContext;
+
+
+static void gimp_text_render_vectors (cairo_t *cr,
+ RenderContext *context);
+
+
+GimpVectors *
+gimp_text_vectors_new (GimpImage *image,
+ GimpText *text)
+{
+ GimpVectors *vectors;
+ RenderContext context = { NULL, };
+
+ g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+ g_return_val_if_fail (GIMP_IS_TEXT (text), NULL);
+
+ vectors = gimp_vectors_new (image, NULL);
+
+ if (text->text || text->markup)
+ {
+ GimpTextLayout *layout;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ gdouble xres;
+ gdouble yres;
+ GError *error = NULL;
+
+ if (text->text)
+ gimp_object_set_name_safe (GIMP_OBJECT (vectors), text->text);
+
+ context.vectors = vectors;
+
+ surface = cairo_recording_surface_create (CAIRO_CONTENT_ALPHA, NULL);
+ cr = cairo_create (surface);
+
+ gimp_image_get_resolution (image, &xres, &yres);
+
+ layout = gimp_text_layout_new (text, xres, yres, &error);
+ if (error)
+ {
+ gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, error->message);
+ g_error_free (error);
+ }
+ gimp_text_layout_render (layout, cr, text->base_dir, TRUE);
+ g_object_unref (layout);
+
+ gimp_text_render_vectors (cr, &context);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ if (context.stroke)
+ gimp_stroke_close (context.stroke);
+ }
+
+ return vectors;
+}
+
+
+static inline void
+gimp_text_vector_coords (const double x,
+ const double y,
+ GimpCoords *coords)
+{
+ const GimpCoords default_values = GIMP_COORDS_DEFAULT_VALUES;
+
+ *coords = default_values;
+
+ coords->x = x;
+ coords->y = y;
+}
+
+static gint
+moveto (RenderContext *context,
+ const double x,
+ const double y)
+{
+ GimpCoords start;
+
+#if GIMP_TEXT_DEBUG
+ g_printerr ("moveto %f, %f\n", x, y);
+#endif
+
+ gimp_text_vector_coords (x, y, &start);
+
+ if (context->stroke)
+ gimp_stroke_close (context->stroke);
+
+ context->stroke = gimp_bezier_stroke_new_moveto (&start);
+
+ gimp_vectors_stroke_add (context->vectors, context->stroke);
+ g_object_unref (context->stroke);
+
+ return 0;
+}
+
+static gint
+lineto (RenderContext *context,
+ const double x,
+ const double y)
+{
+ GimpCoords end;
+
+#if GIMP_TEXT_DEBUG
+ g_printerr ("lineto %f, %f\n", x, y);
+#endif
+
+ if (! context->stroke)
+ return 0;
+
+ gimp_text_vector_coords (x, y, &end);
+
+ gimp_bezier_stroke_lineto (context->stroke, &end);
+
+ return 0;
+}
+
+static gint
+cubicto (RenderContext *context,
+ const double x1,
+ const double y1,
+ const double x2,
+ const double y2,
+ const double x3,
+ const double y3)
+{
+ GimpCoords control1;
+ GimpCoords control2;
+ GimpCoords end;
+
+#if GIMP_TEXT_DEBUG
+ g_printerr ("cubicto %f, %f\n", x3, y3);
+#endif
+
+ if (! context->stroke)
+ return 0;
+
+ gimp_text_vector_coords (x1, y1, &control1);
+ gimp_text_vector_coords (x2, y2, &control2);
+ gimp_text_vector_coords (x3, y3, &end);
+
+ gimp_bezier_stroke_cubicto (context->stroke, &control1, &control2, &end);
+
+ return 0;
+}
+
+static gint
+closepath (RenderContext *context)
+{
+#if GIMP_TEXT_DEBUG
+ g_printerr ("moveto\n");
+#endif
+
+ if (! context->stroke)
+ return 0;
+
+ gimp_stroke_close (context->stroke);
+
+ context->stroke = NULL;
+
+ return 0;
+}
+
+static void
+gimp_text_render_vectors (cairo_t *cr,
+ RenderContext *context)
+{
+ cairo_path_t *path;
+ gint i;
+
+ path = cairo_copy_path (cr);
+
+ for (i = 0; i < path->num_data; i += path->data[i].header.length)
+ {
+ cairo_path_data_t *data = &path->data[i];
+
+ /* if the drawing operation is the final moveto of the glyph,
+ * break to avoid creating an empty point. This is because cairo
+ * always adds a moveto after each closepath.
+ */
+ if (i + data->header.length >= path->num_data)
+ break;
+
+ switch (data->header.type)
+ {
+ case CAIRO_PATH_MOVE_TO:
+ moveto (context, data[1].point.x, data[1].point.y);
+ break;
+
+ case CAIRO_PATH_LINE_TO:
+ lineto (context, data[1].point.x, data[1].point.y);
+ break;
+
+ case CAIRO_PATH_CURVE_TO:
+ cubicto (context,
+ data[1].point.x, data[1].point.y,
+ data[2].point.x, data[2].point.y,
+ data[3].point.x, data[3].point.y);
+ break;
+
+ case CAIRO_PATH_CLOSE_PATH:
+ closepath (context);
+ break;
+ }
+ }
+
+ cairo_path_destroy (path);
+}