[AdgLDim] Avoid arrange() on the same data
[adg.git] / adg / adg-font-style.c
blob8fc25351aaa315670778f02f9694cac90c141530
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-font-style
23 * @short_description: Font style related stuff
25 * Contains parameters on how to draw texts such as font family, slanting,
26 * weight, hinting and so on.
29 /**
30 * AdgFontStyle:
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
34 **/
37 #include "adg-font-style.h"
38 #include "adg-font-style-private.h"
39 #include "adg-util.h"
40 #include "adg-intl.h"
42 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_font_style_parent_class)
45 enum {
46 PROP_0,
47 PROP_FAMILY,
48 PROP_SLANT,
49 PROP_WEIGHT,
50 PROP_SIZE,
51 PROP_ANTIALIAS,
52 PROP_SUBPIXEL_ORDER,
53 PROP_HINT_STYLE,
54 PROP_HINT_METRICS
58 static void dispose (GObject *object);
59 static void get_property (GObject *object,
60 guint prop_id,
61 GValue *value,
62 GParamSpec *pspec);
63 static void set_property (GObject *object,
64 guint prop_id,
65 const GValue *value,
66 GParamSpec *pspec);
67 static void apply (AdgStyle *style,
68 cairo_t *cr);
69 static gboolean set_family (AdgFontStyle *font_style,
70 const gchar *family);
71 static gboolean set_slant (AdgFontStyle *font_style,
72 cairo_font_slant_t slant);
73 static gboolean set_weight (AdgFontStyle *font_style,
74 cairo_font_weight_t weight);
75 static gboolean set_size (AdgFontStyle *font_style,
76 gdouble size);
77 static gboolean set_antialias (AdgFontStyle *font_style,
78 cairo_antialias_t antialias);
79 static gboolean set_subpixel_order (AdgFontStyle *font_style,
80 cairo_subpixel_order_t subpixel_order);
81 static gboolean set_hint_style (AdgFontStyle *font_style,
82 cairo_hint_style_t hint_style);
83 static gboolean set_hint_metrics (AdgFontStyle *font_style,
84 cairo_hint_metrics_t hint_metrics);
85 static void unset_face (AdgFontStyle *font_style);
86 static void unset_font (AdgFontStyle *font_style);
89 G_DEFINE_TYPE(AdgFontStyle, adg_font_style, ADG_TYPE_STYLE);
92 static void
93 adg_font_style_class_init(AdgFontStyleClass *klass)
95 GObjectClass *gobject_class;
96 AdgStyleClass *style_class;
97 GParamSpec *param;
99 gobject_class = (GObjectClass *) klass;
100 style_class = (AdgStyleClass *) klass;
102 g_type_class_add_private(klass, sizeof(AdgFontStylePrivate));
104 gobject_class->dispose = dispose;
105 gobject_class->get_property = get_property;
106 gobject_class->set_property = set_property;
108 style_class->apply = apply;
110 param = g_param_spec_string("family",
111 P_("Font Family"),
112 P_("The font family name, encoded in UTF-8"),
113 NULL,
114 G_PARAM_READWRITE);
115 g_object_class_install_property(gobject_class, PROP_FAMILY, param);
117 param = g_param_spec_int("slant",
118 P_("Font Slant"),
119 P_("Variant of a font face based on its slant"),
120 G_MININT, G_MAXINT, CAIRO_FONT_SLANT_NORMAL,
121 G_PARAM_READWRITE);
122 g_object_class_install_property(gobject_class, PROP_SLANT, param);
124 param = g_param_spec_int("weight",
125 P_("Font Weight"),
126 P_("Variant of a font face based on its weight"),
127 G_MININT, G_MAXINT, CAIRO_FONT_WEIGHT_NORMAL,
128 G_PARAM_READWRITE);
129 g_object_class_install_property(gobject_class, PROP_WEIGHT, param);
131 param = g_param_spec_double("size",
132 P_("Font Size"),
133 P_("Font size in user space units"),
134 0, G_MAXDOUBLE, 10,
135 G_PARAM_READWRITE);
136 g_object_class_install_property(gobject_class, PROP_SIZE, param);
138 param = g_param_spec_int("antialias",
139 P_("Font Antialiasing Mode"),
140 P_("Type of antialiasing to do when rendering text"),
141 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
142 G_PARAM_READWRITE);
143 g_object_class_install_property(gobject_class, PROP_ANTIALIAS, param);
145 param = g_param_spec_int("subpixel-order",
146 P_("Font Subpixel Order"),
147 P_("The order of color elements within each pixel on the display device when rendering with subpixel antialiasing mode"),
148 G_MININT, G_MAXINT,
149 CAIRO_SUBPIXEL_ORDER_DEFAULT,
150 G_PARAM_READWRITE);
151 g_object_class_install_property(gobject_class, PROP_SUBPIXEL_ORDER, param);
153 param = g_param_spec_int("hint-style",
154 P_("Type of Hinting"),
155 P_("How outlines must fit to the pixel grid in order to improve the glyph appearance"),
156 G_MININT, G_MAXINT, CAIRO_HINT_STYLE_DEFAULT,
157 G_PARAM_READWRITE);
158 g_object_class_install_property(gobject_class, PROP_HINT_STYLE, param);
160 param = g_param_spec_int("hint-metrics",
161 P_("Font Metric Hinting"),
162 P_("Whether to hint font metrics, that is align them to integer values in device space"),
163 G_MININT, G_MAXINT,
164 CAIRO_HINT_METRICS_DEFAULT,
165 G_PARAM_READWRITE);
166 g_object_class_install_property(gobject_class, PROP_HINT_METRICS, param);
169 static void
170 adg_font_style_init(AdgFontStyle *font_style)
172 AdgFontStylePrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(font_style,
173 ADG_TYPE_FONT_STYLE,
174 AdgFontStylePrivate);
176 data->family = NULL;
177 data->slant = CAIRO_FONT_SLANT_NORMAL;
178 data->weight = CAIRO_FONT_WEIGHT_NORMAL;
179 data->size = 10;
180 data->antialias = CAIRO_ANTIALIAS_DEFAULT;
181 data->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
182 data->hint_style = CAIRO_HINT_STYLE_DEFAULT;
183 data->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
184 data->font = NULL;
186 font_style->data = data;
189 static void
190 dispose(GObject *object)
192 AdgFontStyle *font_style = (AdgFontStyle *) object;
194 unset_font(font_style);
195 unset_face(font_style);
197 if (PARENT_OBJECT_CLASS->dispose != NULL)
198 PARENT_OBJECT_CLASS->dispose(object);
202 static void
203 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
205 AdgFontStylePrivate *data = ((AdgFontStyle *) object)->data;
207 switch (prop_id) {
208 case PROP_FAMILY:
209 g_value_set_string(value, data->family);
210 break;
211 case PROP_SLANT:
212 g_value_set_int(value, data->slant);
213 break;
214 case PROP_WEIGHT:
215 g_value_set_int(value, data->weight);
216 break;
217 case PROP_SIZE:
218 g_value_set_double(value, data->size);
219 break;
220 case PROP_ANTIALIAS:
221 g_value_set_int(value, data->antialias);
222 break;
223 case PROP_SUBPIXEL_ORDER:
224 g_value_set_int(value, data->subpixel_order);
225 break;
226 case PROP_HINT_STYLE:
227 g_value_set_int(value, data->hint_style);
228 break;
229 case PROP_HINT_METRICS:
230 g_value_set_int(value, data->hint_metrics);
231 break;
232 default:
233 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
234 break;
238 static void
239 set_property(GObject *object,
240 guint prop_id, const GValue *value, GParamSpec *pspec)
242 AdgFontStyle *font_style;
243 AdgFontStylePrivate *data;
245 font_style = (AdgFontStyle *) object;
246 data = font_style->data;
248 switch (prop_id) {
249 case PROP_FAMILY:
250 set_family(font_style, g_value_get_string(value));
251 break;
252 case PROP_SLANT:
253 set_slant(font_style, g_value_get_int(value));
254 break;
255 case PROP_WEIGHT:
256 set_weight(font_style, g_value_get_int(value));
257 break;
258 case PROP_SIZE:
259 set_size(font_style, g_value_get_double(value));
260 break;
261 case PROP_ANTIALIAS:
262 set_antialias(font_style, g_value_get_int(value));
263 break;
264 case PROP_SUBPIXEL_ORDER:
265 set_subpixel_order(font_style, g_value_get_int(value));
266 break;
267 case PROP_HINT_STYLE:
268 set_hint_style(font_style, g_value_get_int(value));
269 break;
270 case PROP_HINT_METRICS:
271 set_hint_metrics(font_style, g_value_get_int(value));
272 break;
273 default:
274 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
275 break;
281 * adg_font_style_new:
283 * Constructs a new font style initialized with default params.
285 * Returns: a new font style
287 AdgStyle *
288 adg_font_style_new(void)
290 return g_object_new(ADG_TYPE_FONT_STYLE, NULL);
294 * adg_font_style_font:
295 * @font_style: an #AdgFontStyle object
297 * Gets the scaled font of @font_style. The returned font is
298 * owned by @font_style and must not be destroyed by the caller.
300 * Returns: the scaled font
302 cairo_scaled_font_t *
303 adg_font_style_font(AdgFontStyle *font_style, const AdgMatrix *ctm)
305 AdgFontStylePrivate *data;
306 cairo_font_options_t *options;
307 AdgMatrix matrix;
309 data = font_style->data;
311 /* Check for cached font */
312 if (data->font != NULL) {
313 AdgMatrix font_ctm;
315 cairo_scaled_font_get_ctm(data->font, &font_ctm);
317 /* The scaled font is valid only if the two ctm match */
318 if (ctm->xx == font_ctm.xx && ctm->yy == font_ctm.yy &&
319 ctm->xy == font_ctm.xy && ctm->yx == font_ctm.yx)
320 return data->font;
322 /* No valid cache found: rebuild the scaled font */
323 unset_font(font_style);
326 if (data->face == NULL) {
327 const gchar *family = data->family != NULL ? data->family : "";
329 data->face = cairo_toy_font_face_create(family, data->slant,
330 data->weight);
333 cairo_matrix_init_scale(&matrix, data->size, data->size);
334 options = cairo_font_options_create();
336 cairo_font_options_set_antialias(options, data->antialias);
337 cairo_font_options_set_subpixel_order(options, data->subpixel_order);
338 cairo_font_options_set_hint_style(options, data->hint_style);
339 cairo_font_options_set_hint_metrics(options, data->hint_metrics);
341 data->font = cairo_scaled_font_create(data->face, &matrix, ctm, options);
343 cairo_font_options_destroy(options);
345 return data->font;
349 * adg_font_style_get_family:
350 * @font_style: an #AdgFontStyle object
352 * Gets the family of @font_style. The returned pointer refers to
353 * internally managed text that must not be modified or freed.
355 * Returns: the requested family
357 const gchar *
358 adg_font_style_get_family(AdgFontStyle *font_style)
360 AdgFontStylePrivate *data;
362 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style), NULL);
364 data = font_style->data;
366 return data->family;
370 * adg_font_style_set_family:
371 * @font_style: an #AdgFontStyle object
372 * @family: the new family
374 * Sets a new family.
376 void
377 adg_font_style_set_family(AdgFontStyle *font_style, const gchar *family)
379 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
381 if (set_family(font_style, family))
382 g_object_notify((GObject *) font_style, "family");
386 * adg_font_style_get_slant:
387 * @font_style: an #AdgFontStyle object
389 * Gets the slant variant of @font_style.
391 * Returns: the slant variant
393 cairo_font_slant_t
394 adg_font_style_get_slant(AdgFontStyle *font_style)
396 AdgFontStylePrivate *data;
398 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
399 CAIRO_FONT_SLANT_NORMAL);
401 data = font_style->data;
403 return data->slant;
407 * adg_font_style_set_slant:
408 * @font_style: an #AdgFontStyle object
409 * @slant: the new slant
411 * Sets a new slant variant on @font_style.
413 void
414 adg_font_style_set_slant(AdgFontStyle *font_style,
415 cairo_font_slant_t slant)
417 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
419 if (set_slant(font_style, slant))
420 g_object_notify((GObject *) font_style, "slant");
424 * adg_font_style_get_weight:
425 * @font_style: an #AdgFontStyle object
427 * Gets the weight variant of @font_style.
429 * Returns: the weight variant
431 cairo_font_weight_t
432 adg_font_style_get_weight(AdgFontStyle *font_style)
434 AdgFontStylePrivate *data;
436 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
437 CAIRO_FONT_WEIGHT_NORMAL);
439 data = font_style->data;
441 return data->weight;
445 * adg_font_style_set_weight:
446 * @font_style: an #AdgFontStyle object
447 * @weight: the new weight
449 * Sets a new weight variant on @font_style.
451 void
452 adg_font_style_set_weight(AdgFontStyle *font_style,
453 cairo_font_weight_t weight)
455 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
457 if (set_weight(font_style, weight))
458 g_object_notify((GObject *) font_style, "weight");
462 * adg_font_style_get_size:
463 * @font_style: an #AdgFontStyle object
465 * Gets the size (in global space) of @font_style.
467 * Returns: the size variant
469 gdouble
470 adg_font_style_get_size(AdgFontStyle *font_style)
472 AdgFontStylePrivate *data;
474 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style), 0.);
476 data = font_style->data;
478 return data->size;
482 * adg_font_style_set_size:
483 * @font_style: an #AdgFontStyle object
484 * @size: the new size
486 * Sets a new size (in global space) on @font_style.
488 void
489 adg_font_style_set_size(AdgFontStyle *font_style, gdouble size)
491 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
493 if (set_size(font_style, size))
494 g_object_notify((GObject *) font_style, "size");
498 * adg_font_style_get_antialias:
499 * @font_style: an #AdgFontStyle object
501 * Gets the antialias mode used.
503 * Returns: the requested antialias mode
505 cairo_antialias_t
506 adg_font_style_get_antialias(AdgFontStyle *font_style)
508 AdgFontStylePrivate *data;
510 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
511 CAIRO_ANTIALIAS_DEFAULT);
513 data = font_style->data;
515 return data->antialias;
519 * adg_font_style_set_antialias:
520 * @font_style: an #AdgFontStyle object
521 * @antialias: the new antialias mode
523 * Sets a new antialias mode.
525 void
526 adg_font_style_set_antialias(AdgFontStyle *font_style,
527 cairo_antialias_t antialias)
529 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
531 if (set_antialias(font_style, antialias))
532 g_object_notify((GObject *) font_style, "antialias");
536 * adg_font_style_get_subpixel_order:
537 * @font_style: an #AdgFontStyle object
539 * Gets the subpixel order mode used, that is the order of color elements
540 * within each pixel on the display device when rendering with an
541 * antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL.
543 * Returns: the requested subpixel order mode
545 cairo_subpixel_order_t
546 adg_font_style_get_subpixel_order(AdgFontStyle *font_style)
548 AdgFontStylePrivate *data;
550 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
551 CAIRO_SUBPIXEL_ORDER_DEFAULT);
553 data = font_style->data;
555 return data->subpixel_order;
559 * adg_font_style_set_subpixel_order:
560 * @font_style: an #AdgFontStyle object
561 * @subpixel_order: the new subpixel order mode
563 * Sets a new subpixel order mode.
565 void
566 adg_font_style_set_subpixel_order(AdgFontStyle *font_style,
567 cairo_subpixel_order_t subpixel_order)
569 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
571 if (set_subpixel_order(font_style, subpixel_order))
572 g_object_notify((GObject *) font_style, "subpixel-order");
576 * adg_font_style_get_hint_style:
577 * @font_style: an #AdgFontStyle object
579 * Gets the hint style mode used, that is how to fit outlines
580 * to the pixel grid in order to improve the appearance of the result.
582 * Returns: the requested hint style mode
584 cairo_hint_style_t
585 adg_font_style_get_hint_style(AdgFontStyle *font_style)
587 AdgFontStylePrivate *data;
589 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
590 CAIRO_HINT_STYLE_DEFAULT);
592 data = font_style->data;
594 return data->hint_style;
598 * adg_font_style_set_hint_style:
599 * @font_style: an #AdgFontStyle object
600 * @hint_style: the new hint style mode
602 * Sets a new hint style mode.
604 void
605 adg_font_style_set_hint_style(AdgFontStyle *font_style,
606 cairo_hint_style_t hint_style)
608 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
610 if (set_hint_style(font_style, hint_style))
611 g_object_notify((GObject *) font_style, "hint-style");
615 * adg_font_style_get_hint_metrics:
616 * @font_style: an #AdgFontStyle object
618 * Gets the state on whether to hint font metrics.
620 * Returns: the requested hint metrics state
622 cairo_hint_metrics_t
623 adg_font_style_get_hint_metrics(AdgFontStyle *font_style)
625 AdgFontStylePrivate *data;
627 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
628 CAIRO_HINT_METRICS_DEFAULT);
630 data = font_style->data;
632 return data->hint_metrics;
636 * adg_font_style_set_hint_metrics:
637 * @font_style: an #AdgFontStyle object
638 * @hint_metrics: the new hint metrics state
640 * Sets a new hint metrics state.
642 void
643 adg_font_style_set_hint_metrics(AdgFontStyle *font_style,
644 cairo_hint_metrics_t hint_metrics)
646 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
648 if (set_hint_metrics(font_style, hint_metrics))
649 g_object_notify((GObject *) font_style, "hint-metrics");
653 static void
654 apply(AdgStyle *style, cairo_t *cr)
656 AdgMatrix ctm;
657 cairo_scaled_font_t *font;
659 cairo_get_matrix(cr, &ctm);
660 font = adg_font_style_font((AdgFontStyle *) style, &ctm);
662 cairo_set_scaled_font(cr, font);
665 static gboolean
666 set_family(AdgFontStyle *font_style, const gchar *family)
668 AdgFontStylePrivate *data = font_style->data;
670 if (adg_strcmp(family, data->family) == 0)
671 return FALSE;
673 g_free(data->family);
674 data->family = g_strdup(family);
675 unset_face(font_style);
677 return TRUE;
680 static gboolean
681 set_slant(AdgFontStyle *font_style, cairo_font_slant_t slant)
683 AdgFontStylePrivate *data = font_style->data;
685 if (slant == data->slant)
686 return FALSE;
688 data->slant = slant;
689 unset_face(font_style);
691 return TRUE;
694 static gboolean
695 set_weight(AdgFontStyle *font_style, cairo_font_weight_t weight)
697 AdgFontStylePrivate *data = font_style->data;
699 if (weight == data->weight)
700 return FALSE;
702 data->weight = weight;
703 unset_face(font_style);
705 return TRUE;
708 static gboolean
709 set_size(AdgFontStyle *font_style, gdouble size)
711 AdgFontStylePrivate *data = font_style->data;
713 if (size == data->size)
714 return FALSE;
716 data->size = size;
717 unset_font(font_style);
719 return TRUE;
722 static gboolean
723 set_antialias(AdgFontStyle *font_style, cairo_antialias_t antialias)
725 AdgFontStylePrivate *data = font_style->data;
727 if (antialias == data->antialias)
728 return FALSE;
730 data->antialias = antialias;
731 unset_font(font_style);
733 return TRUE;
736 static gboolean
737 set_subpixel_order(AdgFontStyle *font_style,
738 cairo_subpixel_order_t subpixel_order)
740 AdgFontStylePrivate *data = font_style->data;
742 if (subpixel_order == data->subpixel_order)
743 return FALSE;
745 data->subpixel_order = subpixel_order;
746 unset_font(font_style);
748 return TRUE;
751 static gboolean
752 set_hint_style(AdgFontStyle *font_style, cairo_hint_style_t hint_style)
754 AdgFontStylePrivate *data = font_style->data;
756 if (hint_style == data->hint_style)
757 return FALSE;
759 data->hint_style = hint_style;
760 unset_font(font_style);
762 return TRUE;
765 static gboolean
766 set_hint_metrics(AdgFontStyle *font_style, cairo_hint_metrics_t hint_metrics)
768 AdgFontStylePrivate *data = font_style->data;
770 if (hint_metrics == data->hint_metrics)
771 return FALSE;
773 data->hint_metrics = hint_metrics;
774 unset_font(font_style);
776 return TRUE;
779 static void
780 unset_face(AdgFontStyle *font_style)
782 AdgFontStylePrivate *data = font_style->data;
784 if (data->face == NULL)
785 return;
787 /* Changing the face invalidates the scaled font too */
788 unset_font(font_style);
790 cairo_font_face_destroy(data->face);
791 data->face = NULL;
794 static void
795 unset_font(AdgFontStyle *font_style)
797 AdgFontStylePrivate *data = font_style->data;
799 if (data->font == NULL)
800 return;
802 cairo_scaled_font_destroy(data->font);
803 data->font = NULL;