diff options
Diffstat (limited to 'app/text/gimptext-vectors.c')
-rw-r--r-- | app/text/gimptext-vectors.c | 255 |
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); +} |