1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 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.
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.
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
37 #include "adg-internal.h"
38 #include "adg-font-style.h"
39 #include "adg-font-style-private.h"
40 #include "adg-dress-builtins.h"
43 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_font_style_parent_class)
60 static void dispose (GObject
*object
);
61 static void get_property (GObject
*object
,
65 static void set_property (GObject
*object
,
69 static void apply (AdgStyle
*style
,
72 static gboolean
set_family (AdgFontStyle
*font_style
,
74 static gboolean
set_slant (AdgFontStyle
*font_style
,
75 cairo_font_slant_t slant
);
76 static gboolean
set_weight (AdgFontStyle
*font_style
,
77 cairo_font_weight_t weight
);
78 static gboolean
set_size (AdgFontStyle
*font_style
,
80 static gboolean
set_antialias (AdgFontStyle
*font_style
,
81 cairo_antialias_t antialias
);
82 static gboolean
set_subpixel_order (AdgFontStyle
*font_style
,
83 cairo_subpixel_order_t subpixel_order
);
84 static gboolean
set_hint_style (AdgFontStyle
*font_style
,
85 cairo_hint_style_t hint_style
);
86 static gboolean
set_hint_metrics (AdgFontStyle
*font_style
,
87 cairo_hint_metrics_t hint_metrics
);
88 static void unset_face (AdgFontStyle
*font_style
);
89 static void unset_font (AdgFontStyle
*font_style
);
92 G_DEFINE_TYPE(AdgFontStyle
, adg_font_style
, ADG_TYPE_STYLE
);
96 adg_font_style_class_init(AdgFontStyleClass
*klass
)
98 GObjectClass
*gobject_class
;
99 AdgStyleClass
*style_class
;
102 gobject_class
= (GObjectClass
*) klass
;
103 style_class
= (AdgStyleClass
*) klass
;
105 g_type_class_add_private(klass
, sizeof(AdgFontStylePrivate
));
107 gobject_class
->dispose
= dispose
;
108 gobject_class
->get_property
= get_property
;
109 gobject_class
->set_property
= set_property
;
111 style_class
->apply
= apply
;
113 param
= adg_param_spec_dress("color-dress",
115 P_("The color dress to bind to this font style"),
118 g_object_class_install_property(gobject_class
, PROP_COLOR_DRESS
, param
);
120 param
= g_param_spec_string("family",
122 P_("The font family name, encoded in UTF-8"),
125 g_object_class_install_property(gobject_class
, PROP_FAMILY
, param
);
127 param
= g_param_spec_int("slant",
129 P_("Variant of a font face based on its slant"),
130 G_MININT
, G_MAXINT
, CAIRO_FONT_SLANT_NORMAL
,
132 g_object_class_install_property(gobject_class
, PROP_SLANT
, param
);
134 param
= g_param_spec_int("weight",
136 P_("Variant of a font face based on its weight"),
137 G_MININT
, G_MAXINT
, CAIRO_FONT_WEIGHT_NORMAL
,
139 g_object_class_install_property(gobject_class
, PROP_WEIGHT
, param
);
141 param
= g_param_spec_double("size",
143 P_("Font size in user space units"),
146 g_object_class_install_property(gobject_class
, PROP_SIZE
, param
);
148 param
= g_param_spec_int("antialias",
149 P_("Font Antialiasing Mode"),
150 P_("Type of antialiasing to do when rendering text"),
151 G_MININT
, G_MAXINT
, CAIRO_ANTIALIAS_DEFAULT
,
153 g_object_class_install_property(gobject_class
, PROP_ANTIALIAS
, param
);
155 param
= g_param_spec_int("subpixel-order",
156 P_("Font Subpixel Order"),
157 P_("The order of color elements within each pixel on the display device when rendering with subpixel antialiasing mode"),
159 CAIRO_SUBPIXEL_ORDER_DEFAULT
,
161 g_object_class_install_property(gobject_class
, PROP_SUBPIXEL_ORDER
, param
);
163 param
= g_param_spec_int("hint-style",
164 P_("Type of Hinting"),
165 P_("How outlines must fit to the pixel grid in order to improve the glyph appearance"),
166 G_MININT
, G_MAXINT
, CAIRO_HINT_STYLE_DEFAULT
,
168 g_object_class_install_property(gobject_class
, PROP_HINT_STYLE
, param
);
170 param
= g_param_spec_int("hint-metrics",
171 P_("Font Metric Hinting"),
172 P_("Whether to hint font metrics, that is align them to integer values in device space"),
174 CAIRO_HINT_METRICS_DEFAULT
,
176 g_object_class_install_property(gobject_class
, PROP_HINT_METRICS
, param
);
180 adg_font_style_init(AdgFontStyle
*font_style
)
182 AdgFontStylePrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(font_style
,
184 AdgFontStylePrivate
);
186 data
->color_dress
= ADG_DRESS_COLOR
;
188 data
->slant
= CAIRO_FONT_SLANT_NORMAL
;
189 data
->weight
= CAIRO_FONT_WEIGHT_NORMAL
;
191 data
->antialias
= CAIRO_ANTIALIAS_DEFAULT
;
192 data
->subpixel_order
= CAIRO_SUBPIXEL_ORDER_DEFAULT
;
193 data
->hint_style
= CAIRO_HINT_STYLE_DEFAULT
;
194 data
->hint_metrics
= CAIRO_HINT_METRICS_DEFAULT
;
197 font_style
->data
= data
;
201 dispose(GObject
*object
)
203 AdgFontStyle
*font_style
= (AdgFontStyle
*) object
;
205 unset_font(font_style
);
206 unset_face(font_style
);
208 if (PARENT_OBJECT_CLASS
->dispose
)
209 PARENT_OBJECT_CLASS
->dispose(object
);
213 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
215 AdgFontStylePrivate
*data
= ((AdgFontStyle
*) object
)->data
;
218 case PROP_COLOR_DRESS
:
219 g_value_set_int(value
, data
->color_dress
);
222 g_value_set_string(value
, data
->family
);
225 g_value_set_int(value
, data
->slant
);
228 g_value_set_int(value
, data
->weight
);
231 g_value_set_double(value
, data
->size
);
234 g_value_set_int(value
, data
->antialias
);
236 case PROP_SUBPIXEL_ORDER
:
237 g_value_set_int(value
, data
->subpixel_order
);
239 case PROP_HINT_STYLE
:
240 g_value_set_int(value
, data
->hint_style
);
242 case PROP_HINT_METRICS
:
243 g_value_set_int(value
, data
->hint_metrics
);
246 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
252 set_property(GObject
*object
,
253 guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
255 AdgFontStyle
*font_style
;
256 AdgFontStylePrivate
*data
;
258 font_style
= (AdgFontStyle
*) object
;
259 data
= font_style
->data
;
262 case PROP_COLOR_DRESS
:
263 adg_dress_set(&data
->color_dress
, g_value_get_int(value
));
266 set_family(font_style
, g_value_get_string(value
));
269 set_slant(font_style
, g_value_get_int(value
));
272 set_weight(font_style
, g_value_get_int(value
));
275 set_size(font_style
, g_value_get_double(value
));
278 set_antialias(font_style
, g_value_get_int(value
));
280 case PROP_SUBPIXEL_ORDER
:
281 set_subpixel_order(font_style
, g_value_get_int(value
));
283 case PROP_HINT_STYLE
:
284 set_hint_style(font_style
, g_value_get_int(value
));
286 case PROP_HINT_METRICS
:
287 set_hint_metrics(font_style
, g_value_get_int(value
));
290 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
297 * adg_font_style_new:
299 * Constructs a new font style initialized with default params.
301 * Returns: a newly created font style
304 adg_font_style_new(void)
306 return g_object_new(ADG_TYPE_FONT_STYLE
, NULL
);
310 * adg_font_style_get_scaled_font:
311 * @font_style: an #AdgFontStyle object
312 * @ctm: the current transformation matrix
314 * Gets the scaled font of @font_style. The returned font is
315 * owned by @font_style and must not be destroyed by the caller.
317 * Returns: the scaled font
319 cairo_scaled_font_t
*
320 adg_font_style_get_scaled_font(AdgFontStyle
*font_style
, const AdgMatrix
*ctm
)
322 AdgFontStylePrivate
*data
;
323 cairo_font_options_t
*options
;
326 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), NULL
);
327 g_return_val_if_fail(ctm
!= NULL
, NULL
);
329 data
= font_style
->data
;
331 /* Check for cached font */
332 if (data
->font
!= NULL
) {
335 cairo_scaled_font_get_ctm(data
->font
, &font_ctm
);
337 /* The scaled font is valid only if the two ctm match */
338 if (ctm
->xx
== font_ctm
.xx
&& ctm
->yy
== font_ctm
.yy
&&
339 ctm
->xy
== font_ctm
.xy
&& ctm
->yx
== font_ctm
.yx
)
342 /* No valid cache found: rebuild the scaled font */
343 unset_font(font_style
);
346 if (data
->face
== NULL
) {
347 const gchar
*family
= data
->family
!= NULL
? data
->family
: "";
349 data
->face
= cairo_toy_font_face_create(family
, data
->slant
,
353 cairo_matrix_init_scale(&matrix
, data
->size
, data
->size
);
354 options
= cairo_font_options_create();
356 cairo_font_options_set_antialias(options
, data
->antialias
);
357 cairo_font_options_set_subpixel_order(options
, data
->subpixel_order
);
358 cairo_font_options_set_hint_style(options
, data
->hint_style
);
359 cairo_font_options_set_hint_metrics(options
, data
->hint_metrics
);
361 data
->font
= cairo_scaled_font_create(data
->face
, &matrix
, ctm
, options
);
363 cairo_font_options_destroy(options
);
369 * adg_font_style_set_color_dress:
370 * @font_style: an #AdgFontStyle
371 * @dress: the new color dress to use
373 * Sets a new color dress on @font_style. The new dress
374 * should be related to the original dress: you cannot
375 * set a dress used for font styles to a dress managing
378 * The validation of the new dress is done by calling
379 * adg_dress_are_related() with @dress and the previous
380 * dress as arguments: check out its documentation for
381 * details on what is a related dress.
384 adg_font_style_set_color_dress(AdgFontStyle
*font_style
, AdgDress dress
)
386 AdgFontStylePrivate
*data
;
388 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
390 data
= font_style
->data
;
392 if (adg_dress_set(&data
->color_dress
, dress
))
393 g_object_notify((GObject
*) font_style
, "color-dress");
397 * adg_font_style_get_color_dress:
398 * @font_style: an #AdgFontStyle
400 * Gets the color dress used by @font_style.
402 * Returns: the current color dress
405 adg_font_style_get_color_dress(AdgFontStyle
*font_style
)
407 AdgFontStylePrivate
*data
;
409 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), ADG_DRESS_UNDEFINED
);
411 data
= font_style
->data
;
413 return data
->color_dress
;
417 * adg_font_style_set_family:
418 * @font_style: an #AdgFontStyle object
419 * @family: the new family
424 adg_font_style_set_family(AdgFontStyle
*font_style
, const gchar
*family
)
426 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
428 if (set_family(font_style
, family
))
429 g_object_notify((GObject
*) font_style
, "family");
433 * adg_font_style_get_family:
434 * @font_style: an #AdgFontStyle object
436 * Gets the family of @font_style. The returned pointer refers to
437 * internally managed text that must not be modified or freed.
439 * Returns: the requested family
442 adg_font_style_get_family(AdgFontStyle
*font_style
)
444 AdgFontStylePrivate
*data
;
446 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), NULL
);
448 data
= font_style
->data
;
454 * adg_font_style_set_slant:
455 * @font_style: an #AdgFontStyle object
456 * @slant: the new slant
458 * Sets a new slant variant on @font_style.
461 adg_font_style_set_slant(AdgFontStyle
*font_style
,
462 cairo_font_slant_t slant
)
464 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
466 if (set_slant(font_style
, slant
))
467 g_object_notify((GObject
*) font_style
, "slant");
471 * adg_font_style_get_slant:
472 * @font_style: an #AdgFontStyle object
474 * Gets the slant variant of @font_style.
476 * Returns: the slant variant
479 adg_font_style_get_slant(AdgFontStyle
*font_style
)
481 AdgFontStylePrivate
*data
;
483 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
484 CAIRO_FONT_SLANT_NORMAL
);
486 data
= font_style
->data
;
492 * adg_font_style_set_weight:
493 * @font_style: an #AdgFontStyle object
494 * @weight: the new weight
496 * Sets a new weight variant on @font_style.
499 adg_font_style_set_weight(AdgFontStyle
*font_style
,
500 cairo_font_weight_t weight
)
502 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
504 if (set_weight(font_style
, weight
))
505 g_object_notify((GObject
*) font_style
, "weight");
509 * adg_font_style_get_weight:
510 * @font_style: an #AdgFontStyle object
512 * Gets the weight variant of @font_style.
514 * Returns: the weight variant
517 adg_font_style_get_weight(AdgFontStyle
*font_style
)
519 AdgFontStylePrivate
*data
;
521 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
522 CAIRO_FONT_WEIGHT_NORMAL
);
524 data
= font_style
->data
;
530 * adg_font_style_set_size:
531 * @font_style: an #AdgFontStyle object
532 * @size: the new size
534 * Sets a new size (in global space) on @font_style.
537 adg_font_style_set_size(AdgFontStyle
*font_style
, gdouble size
)
539 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
541 if (set_size(font_style
, size
))
542 g_object_notify((GObject
*) font_style
, "size");
546 * adg_font_style_get_size:
547 * @font_style: an #AdgFontStyle object
549 * Gets the size (in global space) of @font_style.
551 * Returns: the size variant
554 adg_font_style_get_size(AdgFontStyle
*font_style
)
556 AdgFontStylePrivate
*data
;
558 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), 0.);
560 data
= font_style
->data
;
566 * adg_font_style_set_antialias:
567 * @font_style: an #AdgFontStyle object
568 * @antialias: the new antialias mode
570 * Sets a new antialias mode.
573 adg_font_style_set_antialias(AdgFontStyle
*font_style
,
574 cairo_antialias_t antialias
)
576 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
578 if (set_antialias(font_style
, antialias
))
579 g_object_notify((GObject
*) font_style
, "antialias");
583 * adg_font_style_get_antialias:
584 * @font_style: an #AdgFontStyle object
586 * Gets the antialias mode used.
588 * Returns: the requested antialias mode
591 adg_font_style_get_antialias(AdgFontStyle
*font_style
)
593 AdgFontStylePrivate
*data
;
595 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
596 CAIRO_ANTIALIAS_DEFAULT
);
598 data
= font_style
->data
;
600 return data
->antialias
;
604 * adg_font_style_set_subpixel_order:
605 * @font_style: an #AdgFontStyle object
606 * @subpixel_order: the new subpixel order mode
608 * Sets a new subpixel order mode.
611 adg_font_style_set_subpixel_order(AdgFontStyle
*font_style
,
612 cairo_subpixel_order_t subpixel_order
)
614 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
616 if (set_subpixel_order(font_style
, subpixel_order
))
617 g_object_notify((GObject
*) font_style
, "subpixel-order");
621 * adg_font_style_get_subpixel_order:
622 * @font_style: an #AdgFontStyle object
624 * Gets the subpixel order mode used, that is the order of color elements
625 * within each pixel on the display device when rendering with an
626 * antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL.
628 * Returns: the requested subpixel order mode
630 cairo_subpixel_order_t
631 adg_font_style_get_subpixel_order(AdgFontStyle
*font_style
)
633 AdgFontStylePrivate
*data
;
635 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
636 CAIRO_SUBPIXEL_ORDER_DEFAULT
);
638 data
= font_style
->data
;
640 return data
->subpixel_order
;
644 * adg_font_style_set_hint_style:
645 * @font_style: an #AdgFontStyle object
646 * @hint_style: the new hint style mode
648 * Sets a new hint style mode.
651 adg_font_style_set_hint_style(AdgFontStyle
*font_style
,
652 cairo_hint_style_t hint_style
)
654 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
656 if (set_hint_style(font_style
, hint_style
))
657 g_object_notify((GObject
*) font_style
, "hint-style");
661 * adg_font_style_get_hint_style:
662 * @font_style: an #AdgFontStyle object
664 * Gets the hint style mode used, that is how to fit outlines
665 * to the pixel grid in order to improve the appearance of the result.
667 * Returns: the requested hint style mode
670 adg_font_style_get_hint_style(AdgFontStyle
*font_style
)
672 AdgFontStylePrivate
*data
;
674 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
675 CAIRO_HINT_STYLE_DEFAULT
);
677 data
= font_style
->data
;
679 return data
->hint_style
;
683 * adg_font_style_set_hint_metrics:
684 * @font_style: an #AdgFontStyle object
685 * @hint_metrics: the new hint metrics state
687 * Sets a new hint metrics state.
690 adg_font_style_set_hint_metrics(AdgFontStyle
*font_style
,
691 cairo_hint_metrics_t hint_metrics
)
693 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
695 if (set_hint_metrics(font_style
, hint_metrics
))
696 g_object_notify((GObject
*) font_style
, "hint-metrics");
700 * adg_font_style_get_hint_metrics:
701 * @font_style: an #AdgFontStyle object
703 * Gets the state on whether to hint font metrics.
705 * Returns: the requested hint metrics state
708 adg_font_style_get_hint_metrics(AdgFontStyle
*font_style
)
710 AdgFontStylePrivate
*data
;
712 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
713 CAIRO_HINT_METRICS_DEFAULT
);
715 data
= font_style
->data
;
717 return data
->hint_metrics
;
722 apply(AdgStyle
*style
, AdgEntity
*entity
, cairo_t
*cr
)
724 AdgFontStyle
*font_style
;
725 AdgFontStylePrivate
*data
;
727 cairo_scaled_font_t
*font
;
729 font_style
= (AdgFontStyle
*) style
;
730 data
= font_style
->data
;
732 adg_entity_apply_dress(entity
, data
->color_dress
, cr
);
734 cairo_get_matrix(cr
, &ctm
);
735 font
= adg_font_style_get_scaled_font((AdgFontStyle
*) style
, &ctm
);
737 cairo_set_scaled_font(cr
, font
);
741 set_family(AdgFontStyle
*font_style
, const gchar
*family
)
743 AdgFontStylePrivate
*data
= font_style
->data
;
745 if (adg_strcmp(family
, data
->family
) == 0)
748 g_free(data
->family
);
749 data
->family
= g_strdup(family
);
750 unset_face(font_style
);
756 set_slant(AdgFontStyle
*font_style
, cairo_font_slant_t slant
)
758 AdgFontStylePrivate
*data
= font_style
->data
;
760 if (slant
== data
->slant
)
764 unset_face(font_style
);
770 set_weight(AdgFontStyle
*font_style
, cairo_font_weight_t weight
)
772 AdgFontStylePrivate
*data
= font_style
->data
;
774 if (weight
== data
->weight
)
777 data
->weight
= weight
;
778 unset_face(font_style
);
784 set_size(AdgFontStyle
*font_style
, gdouble size
)
786 AdgFontStylePrivate
*data
= font_style
->data
;
788 /* A better approach would be to use the GParamSpec of this property */
789 g_return_val_if_fail(size
>= 0, FALSE
);
791 if (size
== data
->size
)
795 unset_font(font_style
);
801 set_antialias(AdgFontStyle
*font_style
, cairo_antialias_t antialias
)
803 AdgFontStylePrivate
*data
= font_style
->data
;
805 if (antialias
== data
->antialias
)
808 data
->antialias
= antialias
;
809 unset_font(font_style
);
815 set_subpixel_order(AdgFontStyle
*font_style
,
816 cairo_subpixel_order_t subpixel_order
)
818 AdgFontStylePrivate
*data
= font_style
->data
;
820 if (subpixel_order
== data
->subpixel_order
)
823 data
->subpixel_order
= subpixel_order
;
824 unset_font(font_style
);
830 set_hint_style(AdgFontStyle
*font_style
, cairo_hint_style_t hint_style
)
832 AdgFontStylePrivate
*data
= font_style
->data
;
834 if (hint_style
== data
->hint_style
)
837 data
->hint_style
= hint_style
;
838 unset_font(font_style
);
844 set_hint_metrics(AdgFontStyle
*font_style
, cairo_hint_metrics_t hint_metrics
)
846 AdgFontStylePrivate
*data
= font_style
->data
;
848 if (hint_metrics
== data
->hint_metrics
)
851 data
->hint_metrics
= hint_metrics
;
852 unset_font(font_style
);
858 unset_face(AdgFontStyle
*font_style
)
860 AdgFontStylePrivate
*data
= font_style
->data
;
862 if (data
->face
== NULL
)
865 /* Changing the face invalidates the scaled font too */
866 unset_font(font_style
);
868 cairo_font_face_destroy(data
->face
);
873 unset_font(AdgFontStyle
*font_style
)
875 AdgFontStylePrivate
*data
= font_style
->data
;
877 if (data
->font
== NULL
)
880 cairo_scaled_font_destroy(data
->font
);