adg: use G_PRIVATE_ADD and friends
[adg.git] / src / adg / adg-font-style.c
blob564ffd8ae64177c443811e80430e2f270f49f114
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2019 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.
28 * Since: 1.0
31 /**
32 * AdgFontStyle:
34 * All fields are private and should not be used directly.
35 * Use its public methods instead.
37 * Since: 1.0
38 **/
41 #include "adg-internal.h"
42 #include "adg-style.h"
43 #include "adg-dress.h"
44 #include "adg-param-dress.h"
46 #include "adg-font-style.h"
47 #include "adg-font-style-private.h"
50 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_font_style_parent_class)
53 G_DEFINE_TYPE_WITH_PRIVATE(AdgFontStyle, adg_font_style, ADG_TYPE_STYLE)
55 enum {
56 PROP_0,
57 PROP_COLOR_DRESS,
58 PROP_FAMILY,
59 PROP_SLANT,
60 PROP_WEIGHT,
61 PROP_SIZE,
62 PROP_ANTIALIAS,
63 PROP_SUBPIXEL_ORDER,
64 PROP_HINT_STYLE,
65 PROP_HINT_METRICS
69 static void _adg_get_property (GObject *object,
70 guint prop_id,
71 GValue *value,
72 GParamSpec *pspec);
73 static void _adg_set_property (GObject *object,
74 guint prop_id,
75 const GValue *value,
76 GParamSpec *pspec);
77 static void _adg_invalidate (AdgStyle *style);
78 static void _adg_apply (AdgStyle *style,
79 AdgEntity *entity,
80 cairo_t *cr);
83 static void
84 adg_font_style_class_init(AdgFontStyleClass *klass)
86 GObjectClass *gobject_class;
87 AdgStyleClass *style_class;
88 GParamSpec *param;
90 gobject_class = (GObjectClass *) klass;
91 style_class = (AdgStyleClass *) klass;
93 gobject_class->get_property = _adg_get_property;
94 gobject_class->set_property = _adg_set_property;
96 style_class->invalidate = _adg_invalidate;
97 style_class->apply = _adg_apply;
99 param = adg_param_spec_dress("color-dress",
100 P_("Color Dress"),
101 P_("The fallback color dress to bind to this style"),
102 ADG_DRESS_COLOR,
103 G_PARAM_READWRITE);
104 g_object_class_install_property(gobject_class, PROP_COLOR_DRESS, param);
106 param = g_param_spec_string("family",
107 P_("Font Family"),
108 P_("The font family name, encoded in UTF-8"),
109 NULL,
110 G_PARAM_READWRITE);
111 g_object_class_install_property(gobject_class, PROP_FAMILY, param);
113 param = g_param_spec_int("slant",
114 P_("Font Slant"),
115 P_("Variant of a font face based on its slant"),
116 G_MININT, G_MAXINT, CAIRO_FONT_SLANT_NORMAL,
117 G_PARAM_READWRITE);
118 g_object_class_install_property(gobject_class, PROP_SLANT, param);
120 param = g_param_spec_int("weight",
121 P_("Font Weight"),
122 P_("Variant of a font face based on its weight"),
123 G_MININT, G_MAXINT, CAIRO_FONT_WEIGHT_NORMAL,
124 G_PARAM_READWRITE);
125 g_object_class_install_property(gobject_class, PROP_WEIGHT, param);
127 param = g_param_spec_double("size",
128 P_("Font Size"),
129 P_("Font size in user space units"),
130 0, G_MAXDOUBLE, 10,
131 G_PARAM_READWRITE);
132 g_object_class_install_property(gobject_class, PROP_SIZE, param);
134 param = g_param_spec_int("antialias",
135 P_("Font Antialiasing Mode"),
136 P_("Type of antialiasing to do when rendering text"),
137 G_MININT, G_MAXINT, CAIRO_ANTIALIAS_DEFAULT,
138 G_PARAM_READWRITE);
139 g_object_class_install_property(gobject_class, PROP_ANTIALIAS, param);
141 param = g_param_spec_int("subpixel-order",
142 P_("Font Subpixel Order"),
143 P_("The order of color elements within each pixel on the display device when rendering with subpixel antialiasing mode"),
144 G_MININT, G_MAXINT,
145 CAIRO_SUBPIXEL_ORDER_DEFAULT,
146 G_PARAM_READWRITE);
147 g_object_class_install_property(gobject_class, PROP_SUBPIXEL_ORDER, param);
149 param = g_param_spec_int("hint-style",
150 P_("Type of Hinting"),
151 P_("How outlines must fit to the pixel grid in order to improve the glyph appearance"),
152 G_MININT, G_MAXINT, CAIRO_HINT_STYLE_DEFAULT,
153 G_PARAM_READWRITE);
154 g_object_class_install_property(gobject_class, PROP_HINT_STYLE, param);
156 param = g_param_spec_int("hint-metrics",
157 P_("Font Metric Hinting"),
158 P_("Whether to hint font metrics, that is align them to integer values in device space"),
159 G_MININT, G_MAXINT,
160 CAIRO_HINT_METRICS_DEFAULT,
161 G_PARAM_READWRITE);
162 g_object_class_install_property(gobject_class, PROP_HINT_METRICS, param);
165 static void
166 adg_font_style_init(AdgFontStyle *font_style)
168 AdgFontStylePrivate *data = adg_font_style_get_instance_private(font_style);
169 data->color_dress = ADG_DRESS_COLOR;
170 data->family = NULL;
171 data->slant = CAIRO_FONT_SLANT_NORMAL;
172 data->weight = CAIRO_FONT_WEIGHT_NORMAL;
173 data->size = 10;
174 data->antialias = CAIRO_ANTIALIAS_DEFAULT;
175 data->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
176 data->hint_style = CAIRO_HINT_STYLE_DEFAULT;
177 data->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
178 data->font = NULL;
181 static void
182 _adg_get_property(GObject *object, guint prop_id,
183 GValue *value, GParamSpec *pspec)
185 AdgFontStylePrivate *data = adg_font_style_get_instance_private((AdgFontStyle *) object);
187 switch (prop_id) {
188 case PROP_COLOR_DRESS:
189 g_value_set_enum(value, data->color_dress);
190 break;
191 case PROP_FAMILY:
192 g_value_set_string(value, data->family);
193 break;
194 case PROP_SLANT:
195 g_value_set_int(value, data->slant);
196 break;
197 case PROP_WEIGHT:
198 g_value_set_int(value, data->weight);
199 break;
200 case PROP_SIZE:
201 g_value_set_double(value, data->size);
202 break;
203 case PROP_ANTIALIAS:
204 g_value_set_int(value, data->antialias);
205 break;
206 case PROP_SUBPIXEL_ORDER:
207 g_value_set_int(value, data->subpixel_order);
208 break;
209 case PROP_HINT_STYLE:
210 g_value_set_int(value, data->hint_style);
211 break;
212 case PROP_HINT_METRICS:
213 g_value_set_int(value, data->hint_metrics);
214 break;
215 default:
216 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
217 break;
221 static void
222 _adg_set_property(GObject *object, guint prop_id,
223 const GValue *value, GParamSpec *pspec)
225 AdgStyle *style = (AdgStyle *) object;
226 AdgFontStyle *font_style = (AdgFontStyle *) object;
227 AdgFontStylePrivate *data = adg_font_style_get_instance_private(font_style);
229 switch (prop_id) {
230 case PROP_COLOR_DRESS:
231 data->color_dress = g_value_get_enum(value);
232 break;
233 case PROP_FAMILY:
234 g_free(data->family);
235 data->family = g_value_dup_string(value);
236 adg_style_invalidate(style);
237 break;
238 case PROP_SLANT:
239 data->slant = g_value_get_int(value);
240 adg_style_invalidate(style);
241 break;
242 case PROP_WEIGHT:
243 data->weight = g_value_get_int(value);
244 adg_style_invalidate(style);
245 break;
246 case PROP_SIZE:
247 data->size = g_value_get_double(value);
248 adg_style_invalidate(style);
249 break;
250 case PROP_ANTIALIAS:
251 data->antialias = g_value_get_int(value);
252 adg_style_invalidate(style);
253 break;
254 case PROP_SUBPIXEL_ORDER:
255 data->subpixel_order = g_value_get_int(value);
256 adg_style_invalidate(style);
257 break;
258 case PROP_HINT_STYLE:
259 data->hint_style = g_value_get_int(value);
260 adg_style_invalidate(style);
261 break;
262 case PROP_HINT_METRICS:
263 data->hint_metrics = g_value_get_int(value);
264 adg_style_invalidate(style);
265 break;
266 default:
267 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
268 break;
274 * adg_font_style_new:
276 * Constructs a new font style initialized with default params.
278 * Returns: (transfer full): a newly created font style
280 * Since: 1.0
282 AdgFontStyle *
283 adg_font_style_new(void)
285 return g_object_new(ADG_TYPE_FONT_STYLE, NULL);
289 * adg_font_style_new_options:
290 * @font_style: an #AdgFontStyle object
292 * Creates a new set of #cairo_font_options_t filled with the values
293 * picked from @font_style. The returned value must be freed with
294 * cairo_font_options_destroy().
296 * Returns: (transfer full): a newly allocated list of cairo font options.
298 * Since: 1.0
300 cairo_font_options_t *
301 adg_font_style_new_options(AdgFontStyle *font_style)
303 AdgFontStylePrivate *data;
304 cairo_font_options_t *options;
306 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style), NULL);
308 data = adg_font_style_get_instance_private(font_style);
309 options = cairo_font_options_create();
311 /* Check for cached font */
312 if (data->font != NULL) {
313 cairo_scaled_font_get_font_options(data->font, options);
314 } else {
315 cairo_font_options_set_antialias(options, data->antialias);
316 cairo_font_options_set_subpixel_order(options, data->subpixel_order);
317 cairo_font_options_set_hint_style(options, data->hint_style);
318 cairo_font_options_set_hint_metrics(options, data->hint_metrics);
321 return options;
325 * adg_font_style_get_scaled_font:
326 * @font_style: an #AdgFontStyle object
327 * @ctm: the current transformation matrix
329 * Gets the scaled font of @font_style. The returned font is
330 * owned by @font_style and must not be destroyed by the caller.
332 * Returns: (transfer none): the scaled font.
334 * Since: 1.0
336 cairo_scaled_font_t *
337 adg_font_style_get_scaled_font(AdgFontStyle *font_style,
338 const cairo_matrix_t *ctm)
340 AdgFontStylePrivate *data;
341 cairo_font_options_t *options;
342 cairo_matrix_t matrix;
344 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style), NULL);
345 g_return_val_if_fail(ctm != NULL, NULL);
347 data = adg_font_style_get_instance_private(font_style);
349 /* Check for cached font */
350 if (data->font != NULL) {
351 cairo_matrix_t font_ctm;
353 cairo_scaled_font_get_ctm(data->font, &font_ctm);
355 /* The scaled font is valid only if the two ctm match */
356 if (ctm->xx == font_ctm.xx && ctm->yy == font_ctm.yy &&
357 ctm->xy == font_ctm.xy && ctm->yx == font_ctm.yx)
358 return data->font;
360 /* No valid cache found: rebuild the scaled font */
361 adg_style_invalidate((AdgStyle *) font_style);
364 if (data->face == NULL) {
365 const gchar *family = data->family != NULL ? data->family : "";
367 data->face = cairo_toy_font_face_create(family, data->slant,
368 data->weight);
371 cairo_matrix_init_scale(&matrix, data->size, data->size);
372 options = adg_font_style_new_options(font_style);
373 data->font = cairo_scaled_font_create(data->face, &matrix, ctm, options);
374 cairo_font_options_destroy(options);
376 return data->font;
380 * adg_font_style_set_color_dress:
381 * @font_style: an #AdgFontStyle
382 * @dress: (transfer none): the new color dress to use
384 * Sets a new color dress on @font_style. The new dress
385 * should be related to the original dress: you cannot
386 * set a dress used for font styles to a dress managing
387 * fonts.
389 * The validation of the new dress is done by calling
390 * adg_dress_are_related() with @dress and the previous
391 * dress as arguments: check out its documentation for
392 * details on what is a related dress.
394 * Since: 1.0
396 void
397 adg_font_style_set_color_dress(AdgFontStyle *font_style, AdgDress dress)
399 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
400 g_object_set(font_style, "color-dress", dress, NULL);
404 * adg_font_style_get_color_dress:
405 * @font_style: an #AdgFontStyle
407 * Gets the color dress used by @font_style.
409 * Returns: (transfer none): the current color dress.
411 * Since: 1.0
413 AdgDress
414 adg_font_style_get_color_dress(AdgFontStyle *font_style)
416 AdgFontStylePrivate *data;
418 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style), ADG_DRESS_UNDEFINED);
420 data = adg_font_style_get_instance_private(font_style);
421 return data->color_dress;
425 * adg_font_style_set_family:
426 * @font_style: an #AdgFontStyle object
427 * @family: (transfer none): the new family
429 * Sets a new family.
431 * Since: 1.0
433 void
434 adg_font_style_set_family(AdgFontStyle *font_style, const gchar *family)
436 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
437 g_object_set(font_style, "family", family, NULL);
441 * adg_font_style_get_family:
442 * @font_style: an #AdgFontStyle object
444 * Gets the family of @font_style. The returned pointer refers to
445 * internally managed text that must not be modified or freed.
447 * Returns: (transfer none): the requested family.
449 * Since: 1.0
451 const gchar *
452 adg_font_style_get_family(AdgFontStyle *font_style)
454 AdgFontStylePrivate *data;
456 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style), NULL);
458 data = adg_font_style_get_instance_private(font_style);
459 return data->family;
463 * adg_font_style_set_slant:
464 * @font_style: an #AdgFontStyle object
465 * @slant: (type gint): the new slant
467 * Sets a new slant variant on @font_style.
469 * Since: 1.0
471 void
472 adg_font_style_set_slant(AdgFontStyle *font_style,
473 cairo_font_slant_t slant)
475 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
476 g_object_set(font_style, "slant", slant, NULL);
480 * adg_font_style_get_slant:
481 * @font_style: an #AdgFontStyle object
483 * Gets the slant variant of @font_style.
485 * Returns: (type gint): the slant variant.
487 * Since: 1.0
489 cairo_font_slant_t
490 adg_font_style_get_slant(AdgFontStyle *font_style)
492 AdgFontStylePrivate *data;
494 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
495 CAIRO_FONT_SLANT_NORMAL);
497 data = adg_font_style_get_instance_private(font_style);
498 return data->slant;
502 * adg_font_style_set_weight:
503 * @font_style: an #AdgFontStyle object
504 * @weight: (type gint): the new weight
506 * Sets a new weight variant on @font_style.
508 * Since: 1.0
510 void
511 adg_font_style_set_weight(AdgFontStyle *font_style,
512 cairo_font_weight_t weight)
514 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
515 g_object_set(font_style, "weight", weight, NULL);
519 * adg_font_style_get_weight:
520 * @font_style: an #AdgFontStyle object
522 * Gets the weight variant of @font_style.
524 * Returns: (type gint): the weight variant.
526 * Since: 1.0
528 cairo_font_weight_t
529 adg_font_style_get_weight(AdgFontStyle *font_style)
531 AdgFontStylePrivate *data;
533 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
534 CAIRO_FONT_WEIGHT_NORMAL);
536 data = adg_font_style_get_instance_private(font_style);
537 return data->weight;
541 * adg_font_style_set_size:
542 * @font_style: an #AdgFontStyle object
543 * @size: the new size
545 * Sets a new size (in global space) on @font_style.
547 * Since: 1.0
549 void
550 adg_font_style_set_size(AdgFontStyle *font_style, gdouble size)
552 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
553 g_object_set(font_style, "size", size, NULL);
557 * adg_font_style_get_size:
558 * @font_style: an #AdgFontStyle object
560 * Gets the size (in global space) of @font_style.
562 * Returns: the size variant.
564 * Since: 1.0
566 gdouble
567 adg_font_style_get_size(AdgFontStyle *font_style)
569 AdgFontStylePrivate *data;
571 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style), 0.);
573 data = adg_font_style_get_instance_private(font_style);
574 return data->size;
578 * adg_font_style_set_antialias:
579 * @font_style: an #AdgFontStyle object
580 * @antialias: (type gint): the new antialias mode
582 * Sets a new antialias mode.
584 * Since: 1.0
586 void
587 adg_font_style_set_antialias(AdgFontStyle *font_style,
588 cairo_antialias_t antialias)
590 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
591 g_object_set(font_style, "antialias", antialias, NULL);
595 * adg_font_style_get_antialias:
596 * @font_style: an #AdgFontStyle object
598 * Gets the antialias mode used.
600 * Returns: (type gint): the requested antialias mode.
602 * Since: 1.0
604 cairo_antialias_t
605 adg_font_style_get_antialias(AdgFontStyle *font_style)
607 AdgFontStylePrivate *data;
609 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
610 CAIRO_ANTIALIAS_DEFAULT);
612 data = adg_font_style_get_instance_private(font_style);
613 return data->antialias;
617 * adg_font_style_set_subpixel_order:
618 * @font_style: an #AdgFontStyle object
619 * @subpixel_order: (type gint): the new subpixel order mode
621 * Sets a new subpixel order mode.
623 * Since: 1.0
625 void
626 adg_font_style_set_subpixel_order(AdgFontStyle *font_style,
627 cairo_subpixel_order_t subpixel_order)
629 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
630 g_object_set(font_style, "subpixel-order", subpixel_order, NULL);
634 * adg_font_style_get_subpixel_order:
635 * @font_style: an #AdgFontStyle object
637 * Gets the subpixel order mode used, that is the order of color elements
638 * within each pixel on the display device when rendering with an
639 * antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL.
641 * Returns: (type gint): the requested subpixel order mode.
643 * Since: 1.0
645 cairo_subpixel_order_t
646 adg_font_style_get_subpixel_order(AdgFontStyle *font_style)
648 AdgFontStylePrivate *data;
650 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
651 CAIRO_SUBPIXEL_ORDER_DEFAULT);
653 data = adg_font_style_get_instance_private(font_style);
654 return data->subpixel_order;
658 * adg_font_style_set_hint_style:
659 * @font_style: an #AdgFontStyle object
660 * @hint_style: (type gint): the new hint style mode
662 * Sets a new hint style mode.
664 * Since: 1.0
666 void
667 adg_font_style_set_hint_style(AdgFontStyle *font_style,
668 cairo_hint_style_t hint_style)
670 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
671 g_object_set(font_style, "hint-style", hint_style, NULL);
675 * adg_font_style_get_hint_style:
676 * @font_style: an #AdgFontStyle object
678 * Gets the hint style mode used, that is how to fit outlines
679 * to the pixel grid in order to improve the appearance of the result.
681 * Returns: (type gint): the requested hint style mode.
683 * Since: 1.0
685 cairo_hint_style_t
686 adg_font_style_get_hint_style(AdgFontStyle *font_style)
688 AdgFontStylePrivate *data;
690 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
691 CAIRO_HINT_STYLE_DEFAULT);
693 data = adg_font_style_get_instance_private(font_style);
694 return data->hint_style;
698 * adg_font_style_set_hint_metrics:
699 * @font_style: an #AdgFontStyle object
700 * @hint_metrics: (type gint): the new hint metrics state
702 * Sets a new hint metrics state.
704 * Since: 1.0
706 void
707 adg_font_style_set_hint_metrics(AdgFontStyle *font_style,
708 cairo_hint_metrics_t hint_metrics)
710 g_return_if_fail(ADG_IS_FONT_STYLE(font_style));
711 g_object_set(font_style, "hint-metrics", hint_metrics, NULL);
715 * adg_font_style_get_hint_metrics:
716 * @font_style: an #AdgFontStyle object
718 * Gets the state on whether to hint font metrics.
720 * Returns: (type gint): the requested hint metrics state.
722 * Since: 1.0
724 cairo_hint_metrics_t
725 adg_font_style_get_hint_metrics(AdgFontStyle *font_style)
727 AdgFontStylePrivate *data;
729 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style),
730 CAIRO_HINT_METRICS_DEFAULT);
732 data = adg_font_style_get_instance_private(font_style);
733 return data->hint_metrics;
737 static void
738 _adg_invalidate(AdgStyle *style)
740 AdgFontStyle *font_style = (AdgFontStyle *) style;
741 AdgFontStylePrivate *data = adg_font_style_get_instance_private(font_style);
743 if (data->font != NULL) {
744 cairo_scaled_font_destroy(data->font);
745 data->font = NULL;
748 if (data->face == NULL) {
749 cairo_font_face_destroy(data->face);
750 data->face = NULL;
754 static void
755 _adg_apply(AdgStyle *style, AdgEntity *entity, cairo_t *cr)
757 AdgFontStyle *font_style;
758 AdgFontStylePrivate *data;
759 cairo_matrix_t ctm;
760 cairo_scaled_font_t *font;
762 font_style = (AdgFontStyle *) style;
763 data = adg_font_style_get_instance_private(font_style);
765 adg_entity_apply_dress(entity, data->color_dress, cr);
767 cairo_get_matrix(cr, &ctm);
768 font = adg_font_style_get_scaled_font((AdgFontStyle *) style, &ctm);
770 cairo_set_scaled_font(cr, font);