gimptext-vectors.c 7.75 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * GimpText
 * 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 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <glib-object.h>
#include <pango/pangoft2.h>
26
#include <freetype/ftglyph.h>
Sven Neumann's avatar
Sven Neumann committed
27
#include <freetype/ftoutln.h>
28 29 30 31

#include "text/text-types.h"

#include "core/gimpimage.h"
32 33

#include "vectors/gimpbezierstroke.h"
34
#include "vectors/gimpvectors.h"
35
#include "vectors/gimpanchor.h"
36 37 38 39 40 41 42 43

#include "gimptext.h"
#include "gimptext-private.h"
#include "gimptext-vectors.h"
#include "gimptextlayout.h"
#include "gimptextlayout-render.h"


44 45 46 47 48
/* for compatibility with older freetype versions */
#ifndef FT_GLYPH_FORMAT_OUTLINE
#define FT_GLYPH_FORMAT_OUTLINE ft_glyph_format_outline
#endif

Sven Neumann's avatar
Sven Neumann committed
49 50 51 52 53
typedef struct _RenderContext  RenderContext;

struct _RenderContext
{
  GimpVectors  *vectors;
54 55
  GimpStroke   *stroke;
  GimpAnchor   *anchor;
56 57
  gdouble       offset_x;
  gdouble       offset_y;
Sven Neumann's avatar
Sven Neumann committed
58 59 60 61
};


static void  gimp_text_render_vectors (PangoFont     *font,
62
				       PangoGlyph     glyph,
63 64
				       FT_Int32       flags,
				       FT_Matrix     *matrix,
Sven Neumann's avatar
Sven Neumann committed
65 66 67
				       gint           x,
				       gint           y,
				       RenderContext *context);
68 69 70 71 72 73 74 75


GimpVectors *
gimp_text_vectors_new (GimpImage *image,
		       GimpText  *text)
{
  GimpVectors    *vectors;
  GimpTextLayout *layout;
Sven Neumann's avatar
Sven Neumann committed
76
  RenderContext   context = { 0, };
77 78 79 80 81 82 83 84 85 86 87 88

  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)
    {
      gimp_object_set_name_safe (GIMP_OBJECT (vectors), text->text);

      layout = gimp_text_layout_new (text, image);

Sven Neumann's avatar
Sven Neumann committed
89 90
      context.vectors = vectors;

91 92
      gimp_text_layout_render (layout,
			       (GimpTextRenderFunc) gimp_text_render_vectors,
Sven Neumann's avatar
Sven Neumann committed
93
			       &context);
94 95 96 97 98 99 100 101

      g_object_unref (layout);
    }

  return vectors;
}


102 103 104 105 106 107 108 109 110 111 112 113 114 115
static void
gimp_text_vector_coords (RenderContext   *context,
                         const FT_Vector *vector,
                         GimpCoords      *coords)
{
  coords->x        = context->offset_x + (gdouble) vector->x / 64.0;
  coords->y        = context->offset_y - (gdouble) vector->y / 64.0;
  coords->pressure = 1.0;
  coords->xtilt    = 0.5;
  coords->ytilt    = 0.5;
  coords->wheel    = 0.5;
}

static gint
Sven Neumann's avatar
Sven Neumann committed
116 117 118 119
moveto (FT_Vector *to,
	gpointer   data)
{
  RenderContext *context = (RenderContext *) data;
120 121
  GimpCoords     coords;

122
#if TEXT_DEBUG
123
  g_printerr ("moveto  %f, %f\n", to->x / 64.0, to->y / 64.0);
124
#endif
125 126 127 128 129

  gimp_text_vector_coords (context, to, &coords);

  context->stroke = gimp_bezier_stroke_new ();
  gimp_vectors_stroke_add (context->vectors, context->stroke);
130
  g_object_unref (context->stroke);
131 132

  context->anchor =
133
    gimp_bezier_stroke_extend (context->stroke,
134
                               &coords, NULL, EXTEND_SIMPLE);
135
  context->anchor =
136
    gimp_bezier_stroke_extend (context->stroke,
137
			       &coords, context->anchor, EXTEND_SIMPLE);
138
  context->anchor =
139
    gimp_bezier_stroke_extend (context->stroke,
140
			       &coords, context->anchor, EXTEND_SIMPLE);
Sven Neumann's avatar
Sven Neumann committed
141 142 143 144

  return 0;
}

145
static gint
Sven Neumann's avatar
Sven Neumann committed
146
lineto (FT_Vector *to,
147
	gpointer   data)
Sven Neumann's avatar
Sven Neumann committed
148 149
{
  RenderContext *context = (RenderContext *) data;
150 151
  GimpCoords     coords;

152
#if TEXT_DEBUG
153
  g_printerr ("lineto  %f, %f\n", to->x / 64.0, to->y / 64.0);
154
#endif
155 156 157 158 159 160

  if (! context->stroke)
    return 0;

  gimp_text_vector_coords (context, to, &coords);

161
  context->anchor =
162
    gimp_bezier_stroke_extend (context->stroke,
163 164
                               &coords, context->anchor, EXTEND_SIMPLE);
  context->anchor =
165
    gimp_bezier_stroke_extend (context->stroke,
166
                               &coords, context->anchor, EXTEND_SIMPLE);
167
  context->anchor =
168
    gimp_bezier_stroke_extend (context->stroke,
169
                               &coords, context->anchor, EXTEND_SIMPLE);
Sven Neumann's avatar
Sven Neumann committed
170 171 172 173

  return 0;
}

174
static gint
175
conicto (FT_Vector *ftcontrol,
Sven Neumann's avatar
Sven Neumann committed
176 177 178 179
	 FT_Vector *to,
	 gpointer   data)
{
  RenderContext *context = (RenderContext *) data;
180
  GimpCoords     coords;
181 182 183
  GimpCoords     control;
  GimpCoords     last;
  GList         *l;
184

185
#if TEXT_DEBUG
186
  g_printerr ("conicto %f, %f\n", to->x / 64.0, to->y / 64.0);
187
#endif
188 189 190

  if (! context->stroke)
    return 0;
191 192 193 194
   
  gimp_text_vector_coords (context, ftcontrol, &control);

  last = control;
195

196 197 198 199
  /* Find the last endpoint */
  for (l = g_list_last (context->stroke->anchors); l; l = l->prev)
    {
      GimpAnchor *anchor = l->data;
200

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
      if (anchor->type == GIMP_ANCHOR_ANCHOR)
	{
	  last = anchor->position;
	  break;
	} 
    }
  
  /* interpolate the cubic control point */
  coords =  last;
  coords.x = (last.x + 2 * control.x) * (1.0 / 3.0);
  coords.y = (last.y + 2 * control.y) * (1.0 / 3.0);
  
  context->anchor->position = coords;

  gimp_text_vector_coords (context, to, &last);

  /* interpolate the cubic control point */
  coords =  last;
  coords.x = (last.x + 2 * control.x) * (1.0 / 3.0);
  coords.y = (last.y + 2 * control.y) * (1.0 / 3.0);
  
222
  context->anchor =
223
    gimp_bezier_stroke_extend (context->stroke,
224 225 226
                               &coords, context->anchor, EXTEND_SIMPLE);

  context->anchor =
227
    gimp_bezier_stroke_extend (context->stroke,
228
                               &last, context->anchor, EXTEND_SIMPLE);
229
  context->anchor =
230
    gimp_bezier_stroke_extend (context->stroke,
231
                               &last, context->anchor, EXTEND_SIMPLE);
Sven Neumann's avatar
Sven Neumann committed
232 233 234 235

  return 0;
}

236
static gint
Sven Neumann's avatar
Sven Neumann committed
237 238 239 240 241 242
cubicto (FT_Vector *control1,
	 FT_Vector *control2,
	 FT_Vector *to,
	 gpointer   data)
{
  RenderContext *context = (RenderContext *) data;
243 244
  GimpCoords     coords;

245
#if TEXT_DEBUG
246
  g_printerr ("cubicto %f, %f\n", to->x / 64.0, to->y / 64.0);
247
#endif
248 249 250 251

  if (! context->stroke)
    return 0;

252 253
  gimp_text_vector_coords (context, control1, &coords);

254 255 256 257
  context->anchor->position = coords;

  gimp_text_vector_coords (context, control2, &coords);

258
  context->anchor =
259
    gimp_bezier_stroke_extend (context->stroke,
260 261
                               &coords, context->anchor, EXTEND_SIMPLE);

262 263
  gimp_text_vector_coords (context, to, &coords);

264
  context->anchor =
265
    gimp_bezier_stroke_extend (context->stroke,
266
                               &coords, context->anchor, EXTEND_SIMPLE);
267
  context->anchor =
268
    gimp_bezier_stroke_extend (context->stroke,
269
                               &coords, context->anchor, EXTEND_SIMPLE);
Sven Neumann's avatar
Sven Neumann committed
270 271 272 273 274

  return 0;
}


275
static void
Sven Neumann's avatar
Sven Neumann committed
276
gimp_text_render_vectors (PangoFont     *font,
277
			  PangoGlyph     pango_glyph,
278 279
			  FT_Int32       flags,
			  FT_Matrix     *trafo,
Sven Neumann's avatar
Sven Neumann committed
280 281 282
			  gint           x,
			  gint           y,
			  RenderContext *context)
283
{
284
  const FT_Outline_Funcs  outline_funcs =
Sven Neumann's avatar
Sven Neumann committed
285 286 287 288
  {
    moveto,
    lineto,
    conicto,
289 290 291
    cubicto,
    0,
    0
Sven Neumann's avatar
Sven Neumann committed
292 293
  };

294 295 296
  FT_Face   face;
  FT_Glyph  glyph;

Sven Neumann's avatar
Sven Neumann committed
297 298
  face = pango_ft2_font_get_face (font);

299 300 301 302 303 304 305 306
  FT_Load_Glyph (face, (FT_UInt) pango_glyph, flags);

  FT_Get_Glyph (face->glyph, &glyph);

  if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
    {
      FT_OutlineGlyph outline_glyph = (FT_OutlineGlyph) glyph;

307 308
      context->offset_x = (gdouble) x / PANGO_SCALE;
      context->offset_y = (gdouble) y / PANGO_SCALE;
309 310 311 312 313

      FT_Outline_Decompose (&outline_glyph->outline, &outline_funcs, context);
    }

  FT_Done_Glyph (glyph);
314
}