1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * GimpText
5 * Copyright (C) 2002-2003 Sven Neumann <sven@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include <cairo.h>
26 #include <gegl.h>
27 #include <gdk-pixbuf/gdk-pixbuf.h>
28 #include <pango/pango.h>
29
30 #include "libgimpbase/gimpbase.h"
31 #include "libgimpmath/gimpmath.h"
32 #include "libgimpcolor/gimpcolor.h"
33 #include "libgimpconfig/gimpconfig.h"
34
35 #include "text-types.h"
36
37 #include "core/gimp-memsize.h"
38 #include "core/gimp-utils.h"
39 #include "core/gimpmarshal.h"
40 #include "core/gimpstrokeoptions.h"
41
42 #include "gimptext.h"
43
44
45 enum
46 {
47 PROP_0,
48 PROP_TEXT,
49 PROP_MARKUP,
50 PROP_FONT,
51 PROP_FONT_SIZE,
52 PROP_UNIT,
53 PROP_ANTIALIAS,
54 PROP_HINT_STYLE,
55 PROP_KERNING,
56 PROP_LANGUAGE,
57 PROP_BASE_DIR,
58 PROP_COLOR,
59 PROP_OUTLINE,
60 PROP_JUSTIFICATION,
61 PROP_INDENTATION,
62 PROP_LINE_SPACING,
63 PROP_LETTER_SPACING,
64 PROP_BOX_MODE,
65 PROP_BOX_WIDTH,
66 PROP_BOX_HEIGHT,
67 PROP_BOX_UNIT,
68 PROP_TRANSFORMATION,
69 PROP_OFFSET_X,
70 PROP_OFFSET_Y,
71 PROP_BORDER,
72 /* for backward compatibility */
73 PROP_HINTING
74 };
75
76 enum
77 {
78 CHANGED,
79 LAST_SIGNAL
80 };
81
82
83 static void gimp_text_finalize (GObject *object);
84 static void gimp_text_get_property (GObject *object,
85 guint property_id,
86 GValue *value,
87 GParamSpec *pspec);
88 static void gimp_text_set_property (GObject *object,
89 guint property_id,
90 const GValue *value,
91 GParamSpec *pspec);
92 static void gimp_text_dispatch_properties_changed (GObject *object,
93 guint n_pspecs,
94 GParamSpec **pspecs);
95 static gint64 gimp_text_get_memsize (GimpObject *object,
96 gint64 *gui_size);
97
98
99 G_DEFINE_TYPE_WITH_CODE (GimpText, gimp_text, GIMP_TYPE_OBJECT,
100 G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, NULL))
101
102 #define parent_class gimp_text_parent_class
103
104 static guint text_signals[LAST_SIGNAL] = { 0 };
105
106
107 static void
gimp_text_class_init(GimpTextClass * klass)108 gimp_text_class_init (GimpTextClass *klass)
109 {
110 GObjectClass *object_class = G_OBJECT_CLASS (klass);
111 GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
112 GimpRGB black;
113 GimpMatrix2 identity;
114 gchar *language;
115
116 text_signals[CHANGED] =
117 g_signal_new ("changed",
118 G_TYPE_FROM_CLASS (klass),
119 G_SIGNAL_RUN_FIRST,
120 G_STRUCT_OFFSET (GimpTextClass, changed),
121 NULL, NULL,
122 gimp_marshal_VOID__VOID,
123 G_TYPE_NONE, 0);
124
125 object_class->finalize = gimp_text_finalize;
126 object_class->get_property = gimp_text_get_property;
127 object_class->set_property = gimp_text_set_property;
128 object_class->dispatch_properties_changed = gimp_text_dispatch_properties_changed;
129
130 gimp_object_class->get_memsize = gimp_text_get_memsize;
131
132 gimp_rgba_set (&black, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE);
133 gimp_matrix2_identity (&identity);
134
135 GIMP_CONFIG_PROP_STRING (object_class, PROP_TEXT,
136 "text",
137 NULL, NULL,
138 NULL,
139 GIMP_PARAM_STATIC_STRINGS);
140
141 GIMP_CONFIG_PROP_STRING (object_class, PROP_MARKUP,
142 "markup",
143 NULL, NULL,
144 NULL,
145 GIMP_PARAM_STATIC_STRINGS);
146
147 GIMP_CONFIG_PROP_STRING (object_class, PROP_FONT,
148 "font",
149 NULL, NULL,
150 "Sans-serif",
151 GIMP_PARAM_STATIC_STRINGS);
152
153 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_FONT_SIZE,
154 "font-size",
155 NULL, NULL,
156 0.0, 8192.0, 24.0,
157 GIMP_PARAM_STATIC_STRINGS);
158
159 /* We use the name "font-size-unit" for backward compatibility.
160 * The unit is also used for other sizes in the text object.
161 */
162 GIMP_CONFIG_PROP_UNIT (object_class, PROP_UNIT,
163 "font-size-unit",
164 NULL, NULL,
165 TRUE, FALSE, GIMP_UNIT_PIXEL,
166 GIMP_PARAM_STATIC_STRINGS);
167
168 GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ANTIALIAS,
169 "antialias",
170 NULL, NULL,
171 TRUE,
172 GIMP_PARAM_STATIC_STRINGS);
173
174 GIMP_CONFIG_PROP_ENUM (object_class, PROP_HINT_STYLE,
175 "hint-style",
176 NULL, NULL,
177 GIMP_TYPE_TEXT_HINT_STYLE,
178 GIMP_TEXT_HINT_STYLE_MEDIUM,
179 GIMP_PARAM_STATIC_STRINGS |
180 GIMP_CONFIG_PARAM_DEFAULTS);
181
182 GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_KERNING,
183 "kerning",
184 NULL, NULL,
185 FALSE,
186 GIMP_PARAM_STATIC_STRINGS |
187 GIMP_CONFIG_PARAM_DEFAULTS);
188
189 language = gimp_get_default_language (NULL);
190
191 GIMP_CONFIG_PROP_STRING (object_class, PROP_LANGUAGE,
192 "language",
193 NULL, NULL,
194 language,
195 GIMP_PARAM_STATIC_STRINGS);
196
197 g_free (language);
198
199 GIMP_CONFIG_PROP_ENUM (object_class, PROP_BASE_DIR,
200 "base-direction",
201 NULL, NULL,
202 GIMP_TYPE_TEXT_DIRECTION,
203 GIMP_TEXT_DIRECTION_LTR,
204 GIMP_PARAM_STATIC_STRINGS);
205
206 GIMP_CONFIG_PROP_RGB (object_class, PROP_COLOR,
207 "color",
208 NULL, NULL,
209 FALSE, &black,
210 GIMP_PARAM_STATIC_STRINGS);
211
212 GIMP_CONFIG_PROP_ENUM (object_class, PROP_OUTLINE,
213 "outline",
214 NULL, NULL,
215 GIMP_TYPE_TEXT_OUTLINE,
216 GIMP_TEXT_OUTLINE_NONE,
217 GIMP_PARAM_STATIC_STRINGS |
218 GIMP_CONFIG_PARAM_DEFAULTS);
219
220 GIMP_CONFIG_PROP_ENUM (object_class, PROP_JUSTIFICATION,
221 "justify",
222 NULL, NULL,
223 GIMP_TYPE_TEXT_JUSTIFICATION,
224 GIMP_TEXT_JUSTIFY_LEFT,
225 GIMP_PARAM_STATIC_STRINGS);
226
227 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_INDENTATION,
228 "indent",
229 NULL, NULL,
230 -8192.0, 8192.0, 0.0,
231 GIMP_PARAM_STATIC_STRINGS |
232 GIMP_CONFIG_PARAM_DEFAULTS);
233
234 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LINE_SPACING,
235 "line-spacing",
236 NULL, NULL,
237 -8192.0, 8192.0, 0.0,
238 GIMP_PARAM_STATIC_STRINGS |
239 GIMP_CONFIG_PARAM_DEFAULTS);
240
241 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LETTER_SPACING,
242 "letter-spacing",
243 NULL, NULL,
244 -8192.0, 8192.0, 0.0,
245 GIMP_PARAM_STATIC_STRINGS |
246 GIMP_CONFIG_PARAM_DEFAULTS);
247
248 GIMP_CONFIG_PROP_ENUM (object_class, PROP_BOX_MODE,
249 "box-mode",
250 NULL, NULL,
251 GIMP_TYPE_TEXT_BOX_MODE,
252 GIMP_TEXT_BOX_DYNAMIC,
253 GIMP_PARAM_STATIC_STRINGS);
254
255 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_BOX_WIDTH,
256 "box-width",
257 NULL, NULL,
258 0.0, GIMP_MAX_IMAGE_SIZE, 0.0,
259 GIMP_PARAM_STATIC_STRINGS |
260 GIMP_CONFIG_PARAM_DEFAULTS);
261
262 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_BOX_HEIGHT,
263 "box-height",
264 NULL, NULL,
265 0.0, GIMP_MAX_IMAGE_SIZE, 0.0,
266 GIMP_PARAM_STATIC_STRINGS |
267 GIMP_CONFIG_PARAM_DEFAULTS);
268
269 GIMP_CONFIG_PROP_UNIT (object_class, PROP_BOX_UNIT,
270 "box-unit",
271 NULL, NULL,
272 TRUE, FALSE, GIMP_UNIT_PIXEL,
273 GIMP_PARAM_STATIC_STRINGS);
274
275 GIMP_CONFIG_PROP_MATRIX2 (object_class, PROP_TRANSFORMATION,
276 "transformation",
277 NULL, NULL,
278 &identity,
279 GIMP_PARAM_STATIC_STRINGS |
280 GIMP_CONFIG_PARAM_DEFAULTS);
281
282 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OFFSET_X,
283 "offset-x",
284 NULL, NULL,
285 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
286 GIMP_PARAM_STATIC_STRINGS |
287 GIMP_CONFIG_PARAM_DEFAULTS);
288
289 GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OFFSET_Y,
290 "offset-y",
291 NULL, NULL,
292 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
293 GIMP_PARAM_STATIC_STRINGS |
294 GIMP_CONFIG_PARAM_DEFAULTS);
295
296 /* border does only exist to implement the old text API */
297 g_object_class_install_property (object_class, PROP_BORDER,
298 g_param_spec_int ("border", NULL, NULL,
299 0, GIMP_MAX_IMAGE_SIZE, 0,
300 G_PARAM_CONSTRUCT |
301 GIMP_PARAM_WRITABLE));
302
303 /* the old hinting options have been replaced by 'hint-style' */
304 GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_HINTING,
305 "hinting",
306 NULL, NULL,
307 TRUE,
308 GIMP_PARAM_STATIC_STRINGS);
309 }
310
311 static void
gimp_text_init(GimpText * text)312 gimp_text_init (GimpText *text)
313 {
314 }
315
316 static void
gimp_text_finalize(GObject * object)317 gimp_text_finalize (GObject *object)
318 {
319 GimpText *text = GIMP_TEXT (object);
320
321 g_clear_pointer (&text->text, g_free);
322 g_clear_pointer (&text->markup, g_free);
323 g_clear_pointer (&text->font, g_free);
324 g_clear_pointer (&text->language, g_free);
325
326 G_OBJECT_CLASS (parent_class)->finalize (object);
327 }
328
329 static void
gimp_text_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)330 gimp_text_get_property (GObject *object,
331 guint property_id,
332 GValue *value,
333 GParamSpec *pspec)
334 {
335 GimpText *text = GIMP_TEXT (object);
336
337 switch (property_id)
338 {
339 case PROP_TEXT:
340 g_value_set_string (value, text->text);
341 break;
342 case PROP_MARKUP:
343 g_value_set_string (value, text->markup);
344 break;
345 case PROP_FONT:
346 g_value_set_string (value, text->font);
347 break;
348 case PROP_FONT_SIZE:
349 g_value_set_double (value, text->font_size);
350 break;
351 case PROP_UNIT:
352 g_value_set_int (value, text->unit);
353 break;
354 case PROP_ANTIALIAS:
355 g_value_set_boolean (value, text->antialias);
356 break;
357 case PROP_HINT_STYLE:
358 g_value_set_enum (value, text->hint_style);
359 break;
360 case PROP_KERNING:
361 g_value_set_boolean (value, text->kerning);
362 break;
363 case PROP_BASE_DIR:
364 g_value_set_enum (value, text->base_dir);
365 break;
366 case PROP_LANGUAGE:
367 g_value_set_string (value, text->language);
368 break;
369 case PROP_COLOR:
370 g_value_set_boxed (value, &text->color);
371 break;
372 case PROP_OUTLINE:
373 g_value_set_enum (value, text->outline);
374 break;
375 case PROP_JUSTIFICATION:
376 g_value_set_enum (value, text->justify);
377 break;
378 case PROP_INDENTATION:
379 g_value_set_double (value, text->indent);
380 break;
381 case PROP_LINE_SPACING:
382 g_value_set_double (value, text->line_spacing);
383 break;
384 case PROP_LETTER_SPACING:
385 g_value_set_double (value, text->letter_spacing);
386 break;
387 case PROP_BOX_MODE:
388 g_value_set_enum (value, text->box_mode);
389 break;
390 case PROP_BOX_WIDTH:
391 g_value_set_double (value, text->box_width);
392 break;
393 case PROP_BOX_HEIGHT:
394 g_value_set_double (value, text->box_height);
395 break;
396 case PROP_BOX_UNIT:
397 g_value_set_int (value, text->box_unit);
398 break;
399 case PROP_TRANSFORMATION:
400 g_value_set_boxed (value, &text->transformation);
401 break;
402 case PROP_OFFSET_X:
403 g_value_set_double (value, text->offset_x);
404 break;
405 case PROP_OFFSET_Y:
406 g_value_set_double (value, text->offset_y);
407 break;
408 case PROP_HINTING:
409 g_value_set_boolean (value,
410 text->hint_style != GIMP_TEXT_HINT_STYLE_NONE);
411 break;
412 default:
413 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
414 break;
415 }
416 }
417
418 static void
gimp_text_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)419 gimp_text_set_property (GObject *object,
420 guint property_id,
421 const GValue *value,
422 GParamSpec *pspec)
423 {
424 GimpText *text = GIMP_TEXT (object);
425 GimpRGB *color;
426 GimpMatrix2 *matrix;
427
428 switch (property_id)
429 {
430 case PROP_TEXT:
431 g_free (text->text);
432 text->text = g_value_dup_string (value);
433 if (text->text && text->markup)
434 {
435 g_clear_pointer (&text->markup, g_free);
436 g_object_notify (object, "markup");
437 }
438 break;
439 case PROP_MARKUP:
440 g_free (text->markup);
441 text->markup = g_value_dup_string (value);
442 if (text->markup && text->text)
443 {
444 g_clear_pointer (&text->text, g_free);
445 g_object_notify (object, "text");
446 }
447 break;
448 case PROP_FONT:
449 {
450 const gchar *font = g_value_get_string (value);
451
452 g_free (text->font);
453
454 if (font)
455 {
456 gsize len = strlen (font);
457
458 if (g_str_has_suffix (font, " Not-Rotated"))
459 len -= strlen ( " Not-Rotated");
460
461 text->font = g_strndup (font, len);
462 }
463 else
464 {
465 text->font = NULL;
466 }
467 }
468 break;
469 case PROP_FONT_SIZE:
470 text->font_size = g_value_get_double (value);
471 break;
472 case PROP_UNIT:
473 text->unit = g_value_get_int (value);
474 break;
475 case PROP_ANTIALIAS:
476 text->antialias = g_value_get_boolean (value);
477 break;
478 case PROP_HINT_STYLE:
479 text->hint_style = g_value_get_enum (value);
480 break;
481 case PROP_KERNING:
482 text->kerning = g_value_get_boolean (value);
483 break;
484 case PROP_LANGUAGE:
485 g_free (text->language);
486 text->language = g_value_dup_string (value);
487 break;
488 case PROP_BASE_DIR:
489 text->base_dir = g_value_get_enum (value);
490 break;
491 case PROP_COLOR:
492 color = g_value_get_boxed (value);
493 text->color = *color;
494 break;
495 case PROP_OUTLINE:
496 text->outline = g_value_get_enum (value);
497 break;
498 case PROP_JUSTIFICATION:
499 text->justify = g_value_get_enum (value);
500 break;
501 case PROP_INDENTATION:
502 text->indent = g_value_get_double (value);
503 break;
504 case PROP_LINE_SPACING:
505 text->line_spacing = g_value_get_double (value);
506 break;
507 case PROP_LETTER_SPACING:
508 text->letter_spacing = g_value_get_double (value);
509 break;
510 case PROP_BOX_MODE:
511 text->box_mode = g_value_get_enum (value);
512 break;
513 case PROP_BOX_WIDTH:
514 text->box_width = g_value_get_double (value);
515 break;
516 case PROP_BOX_HEIGHT:
517 text->box_height = g_value_get_double (value);
518 break;
519 case PROP_BOX_UNIT:
520 text->box_unit = g_value_get_int (value);
521 break;
522 case PROP_TRANSFORMATION:
523 matrix = g_value_get_boxed (value);
524 text->transformation = *matrix;
525 break;
526 case PROP_OFFSET_X:
527 text->offset_x = g_value_get_double (value);
528 break;
529 case PROP_OFFSET_Y:
530 text->offset_y = g_value_get_double (value);
531 break;
532 case PROP_BORDER:
533 text->border = g_value_get_int (value);
534 break;
535 case PROP_HINTING:
536 /* interpret "hinting" only if "hint-style" has its default
537 * value, so we don't overwrite a serialized new hint-style with
538 * a compat "hinting" that is only there for old GIMP versions
539 */
540 if (text->hint_style == GIMP_TEXT_HINT_STYLE_MEDIUM)
541 text->hint_style = (g_value_get_boolean (value) ?
542 GIMP_TEXT_HINT_STYLE_MEDIUM :
543 GIMP_TEXT_HINT_STYLE_NONE);
544 break;
545 default:
546 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
547 break;
548 }
549 }
550
551 static void
gimp_text_dispatch_properties_changed(GObject * object,guint n_pspecs,GParamSpec ** pspecs)552 gimp_text_dispatch_properties_changed (GObject *object,
553 guint n_pspecs,
554 GParamSpec **pspecs)
555 {
556 G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
557 n_pspecs, pspecs);
558
559 g_signal_emit (object, text_signals[CHANGED], 0);
560 }
561
562 static gint64
gimp_text_get_memsize(GimpObject * object,gint64 * gui_size)563 gimp_text_get_memsize (GimpObject *object,
564 gint64 *gui_size)
565 {
566 GimpText *text = GIMP_TEXT (object);
567 gint64 memsize = 0;
568
569 memsize += gimp_string_get_memsize (text->text);
570 memsize += gimp_string_get_memsize (text->markup);
571 memsize += gimp_string_get_memsize (text->font);
572 memsize += gimp_string_get_memsize (text->language);
573
574 return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
575 gui_size);
576 }
577
578 void
gimp_text_get_transformation(GimpText * text,GimpMatrix3 * matrix)579 gimp_text_get_transformation (GimpText *text,
580 GimpMatrix3 *matrix)
581 {
582 g_return_if_fail (GIMP_IS_TEXT (text));
583 g_return_if_fail (matrix != NULL);
584
585 matrix->coeff[0][0] = text->transformation.coeff[0][0];
586 matrix->coeff[0][1] = text->transformation.coeff[0][1];
587 matrix->coeff[0][2] = text->offset_x;
588
589 matrix->coeff[1][0] = text->transformation.coeff[1][0];
590 matrix->coeff[1][1] = text->transformation.coeff[1][1];
591 matrix->coeff[1][2] = text->offset_y;
592
593 matrix->coeff[2][0] = 0.0;
594 matrix->coeff[2][1] = 0.0;
595 matrix->coeff[2][2] = 1.0;
596 }
597