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"
42 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_font_style_parent_class)
59 static void dispose (GObject
*object
);
60 static void get_property (GObject
*object
,
64 static void set_property (GObject
*object
,
68 static void apply (AdgStyle
*style
,
71 static gboolean
set_family (AdgFontStyle
*font_style
,
73 static gboolean
set_slant (AdgFontStyle
*font_style
,
74 cairo_font_slant_t slant
);
75 static gboolean
set_weight (AdgFontStyle
*font_style
,
76 cairo_font_weight_t weight
);
77 static gboolean
set_size (AdgFontStyle
*font_style
,
79 static gboolean
set_antialias (AdgFontStyle
*font_style
,
80 cairo_antialias_t antialias
);
81 static gboolean
set_subpixel_order (AdgFontStyle
*font_style
,
82 cairo_subpixel_order_t subpixel_order
);
83 static gboolean
set_hint_style (AdgFontStyle
*font_style
,
84 cairo_hint_style_t hint_style
);
85 static gboolean
set_hint_metrics (AdgFontStyle
*font_style
,
86 cairo_hint_metrics_t hint_metrics
);
87 static void unset_face (AdgFontStyle
*font_style
);
88 static void unset_font (AdgFontStyle
*font_style
);
91 G_DEFINE_TYPE(AdgFontStyle
, adg_font_style
, ADG_TYPE_STYLE
);
95 adg_font_style_class_init(AdgFontStyleClass
*klass
)
97 GObjectClass
*gobject_class
;
98 AdgStyleClass
*style_class
;
101 gobject_class
= (GObjectClass
*) klass
;
102 style_class
= (AdgStyleClass
*) klass
;
104 g_type_class_add_private(klass
, sizeof(AdgFontStylePrivate
));
106 gobject_class
->dispose
= dispose
;
107 gobject_class
->get_property
= get_property
;
108 gobject_class
->set_property
= set_property
;
110 style_class
->apply
= apply
;
112 param
= adg_param_spec_dress("color-dress",
114 P_("The color dress to bind to this font style"),
117 g_object_class_install_property(gobject_class
, PROP_COLOR_DRESS
, param
);
119 param
= g_param_spec_string("family",
121 P_("The font family name, encoded in UTF-8"),
124 g_object_class_install_property(gobject_class
, PROP_FAMILY
, param
);
126 param
= g_param_spec_int("slant",
128 P_("Variant of a font face based on its slant"),
129 G_MININT
, G_MAXINT
, CAIRO_FONT_SLANT_NORMAL
,
131 g_object_class_install_property(gobject_class
, PROP_SLANT
, param
);
133 param
= g_param_spec_int("weight",
135 P_("Variant of a font face based on its weight"),
136 G_MININT
, G_MAXINT
, CAIRO_FONT_WEIGHT_NORMAL
,
138 g_object_class_install_property(gobject_class
, PROP_WEIGHT
, param
);
140 param
= g_param_spec_double("size",
142 P_("Font size in user space units"),
145 g_object_class_install_property(gobject_class
, PROP_SIZE
, param
);
147 param
= g_param_spec_int("antialias",
148 P_("Font Antialiasing Mode"),
149 P_("Type of antialiasing to do when rendering text"),
150 G_MININT
, G_MAXINT
, CAIRO_ANTIALIAS_DEFAULT
,
152 g_object_class_install_property(gobject_class
, PROP_ANTIALIAS
, param
);
154 param
= g_param_spec_int("subpixel-order",
155 P_("Font Subpixel Order"),
156 P_("The order of color elements within each pixel on the display device when rendering with subpixel antialiasing mode"),
158 CAIRO_SUBPIXEL_ORDER_DEFAULT
,
160 g_object_class_install_property(gobject_class
, PROP_SUBPIXEL_ORDER
, param
);
162 param
= g_param_spec_int("hint-style",
163 P_("Type of Hinting"),
164 P_("How outlines must fit to the pixel grid in order to improve the glyph appearance"),
165 G_MININT
, G_MAXINT
, CAIRO_HINT_STYLE_DEFAULT
,
167 g_object_class_install_property(gobject_class
, PROP_HINT_STYLE
, param
);
169 param
= g_param_spec_int("hint-metrics",
170 P_("Font Metric Hinting"),
171 P_("Whether to hint font metrics, that is align them to integer values in device space"),
173 CAIRO_HINT_METRICS_DEFAULT
,
175 g_object_class_install_property(gobject_class
, PROP_HINT_METRICS
, param
);
179 adg_font_style_init(AdgFontStyle
*font_style
)
181 AdgFontStylePrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(font_style
,
183 AdgFontStylePrivate
);
185 data
->color_dress
= ADG_DRESS_COLOR
;
187 data
->slant
= CAIRO_FONT_SLANT_NORMAL
;
188 data
->weight
= CAIRO_FONT_WEIGHT_NORMAL
;
190 data
->antialias
= CAIRO_ANTIALIAS_DEFAULT
;
191 data
->subpixel_order
= CAIRO_SUBPIXEL_ORDER_DEFAULT
;
192 data
->hint_style
= CAIRO_HINT_STYLE_DEFAULT
;
193 data
->hint_metrics
= CAIRO_HINT_METRICS_DEFAULT
;
196 font_style
->data
= data
;
200 dispose(GObject
*object
)
202 AdgFontStyle
*font_style
= (AdgFontStyle
*) object
;
204 unset_font(font_style
);
205 unset_face(font_style
);
207 if (PARENT_OBJECT_CLASS
->dispose
)
208 PARENT_OBJECT_CLASS
->dispose(object
);
212 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
214 AdgFontStylePrivate
*data
= ((AdgFontStyle
*) object
)->data
;
217 case PROP_COLOR_DRESS
:
218 g_value_set_int(value
, data
->color_dress
);
221 g_value_set_string(value
, data
->family
);
224 g_value_set_int(value
, data
->slant
);
227 g_value_set_int(value
, data
->weight
);
230 g_value_set_double(value
, data
->size
);
233 g_value_set_int(value
, data
->antialias
);
235 case PROP_SUBPIXEL_ORDER
:
236 g_value_set_int(value
, data
->subpixel_order
);
238 case PROP_HINT_STYLE
:
239 g_value_set_int(value
, data
->hint_style
);
241 case PROP_HINT_METRICS
:
242 g_value_set_int(value
, data
->hint_metrics
);
245 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
251 set_property(GObject
*object
,
252 guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
254 AdgFontStyle
*font_style
;
255 AdgFontStylePrivate
*data
;
257 font_style
= (AdgFontStyle
*) object
;
258 data
= font_style
->data
;
261 case PROP_COLOR_DRESS
:
262 data
->color_dress
= g_value_get_int(value
);
265 set_family(font_style
, g_value_get_string(value
));
268 set_slant(font_style
, g_value_get_int(value
));
271 set_weight(font_style
, g_value_get_int(value
));
274 set_size(font_style
, g_value_get_double(value
));
277 set_antialias(font_style
, g_value_get_int(value
));
279 case PROP_SUBPIXEL_ORDER
:
280 set_subpixel_order(font_style
, g_value_get_int(value
));
282 case PROP_HINT_STYLE
:
283 set_hint_style(font_style
, g_value_get_int(value
));
285 case PROP_HINT_METRICS
:
286 set_hint_metrics(font_style
, g_value_get_int(value
));
289 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
296 * adg_font_style_new:
298 * Constructs a new font style initialized with default params.
300 * Returns: a newly created font style
303 adg_font_style_new(void)
305 return g_object_new(ADG_TYPE_FONT_STYLE
, NULL
);
309 * adg_font_style_get_scaled_font:
310 * @font_style: an #AdgFontStyle object
311 * @ctm: the current transformation matrix
313 * Gets the scaled font of @font_style. The returned font is
314 * owned by @font_style and must not be destroyed by the caller.
316 * Returns: the scaled font
318 cairo_scaled_font_t
*
319 adg_font_style_get_scaled_font(AdgFontStyle
*font_style
, const AdgMatrix
*ctm
)
321 AdgFontStylePrivate
*data
;
322 cairo_font_options_t
*options
;
325 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), NULL
);
326 g_return_val_if_fail(ctm
!= NULL
, NULL
);
328 data
= font_style
->data
;
330 /* Check for cached font */
331 if (data
->font
!= NULL
) {
334 cairo_scaled_font_get_ctm(data
->font
, &font_ctm
);
336 /* The scaled font is valid only if the two ctm match */
337 if (ctm
->xx
== font_ctm
.xx
&& ctm
->yy
== font_ctm
.yy
&&
338 ctm
->xy
== font_ctm
.xy
&& ctm
->yx
== font_ctm
.yx
)
341 /* No valid cache found: rebuild the scaled font */
342 unset_font(font_style
);
345 if (data
->face
== NULL
) {
346 const gchar
*family
= data
->family
!= NULL
? data
->family
: "";
348 data
->face
= cairo_toy_font_face_create(family
, data
->slant
,
352 cairo_matrix_init_scale(&matrix
, data
->size
, data
->size
);
353 options
= cairo_font_options_create();
355 cairo_font_options_set_antialias(options
, data
->antialias
);
356 cairo_font_options_set_subpixel_order(options
, data
->subpixel_order
);
357 cairo_font_options_set_hint_style(options
, data
->hint_style
);
358 cairo_font_options_set_hint_metrics(options
, data
->hint_metrics
);
360 data
->font
= cairo_scaled_font_create(data
->face
, &matrix
, ctm
, options
);
362 cairo_font_options_destroy(options
);
368 * adg_font_style_set_color_dress:
369 * @font_style: an #AdgFontStyle
370 * @dress: the new color dress to use
372 * Sets a new color dress on @font_style. The new dress
373 * should be related to the original dress: you cannot
374 * set a dress used for font styles to a dress managing
377 * The validation of the new dress is done by calling
378 * adg_dress_are_related() with @dress and the previous
379 * dress as arguments: check out its documentation for
380 * details on what is a related dress.
383 adg_font_style_set_color_dress(AdgFontStyle
*font_style
, AdgDress dress
)
385 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
386 g_object_set((GObject
*) font_style
, "color-dress", dress
, NULL
);
390 * adg_font_style_get_color_dress:
391 * @font_style: an #AdgFontStyle
393 * Gets the color dress used by @font_style.
395 * Returns: the current color dress
398 adg_font_style_get_color_dress(AdgFontStyle
*font_style
)
400 AdgFontStylePrivate
*data
;
402 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), ADG_DRESS_UNDEFINED
);
404 data
= font_style
->data
;
406 return data
->color_dress
;
410 * adg_font_style_set_family:
411 * @font_style: an #AdgFontStyle object
412 * @family: the new family
417 adg_font_style_set_family(AdgFontStyle
*font_style
, const gchar
*family
)
419 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
421 if (set_family(font_style
, family
))
422 g_object_notify((GObject
*) font_style
, "family");
426 * adg_font_style_get_family:
427 * @font_style: an #AdgFontStyle object
429 * Gets the family of @font_style. The returned pointer refers to
430 * internally managed text that must not be modified or freed.
432 * Returns: the requested family
435 adg_font_style_get_family(AdgFontStyle
*font_style
)
437 AdgFontStylePrivate
*data
;
439 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), NULL
);
441 data
= font_style
->data
;
447 * adg_font_style_set_slant:
448 * @font_style: an #AdgFontStyle object
449 * @slant: the new slant
451 * Sets a new slant variant on @font_style.
454 adg_font_style_set_slant(AdgFontStyle
*font_style
,
455 cairo_font_slant_t slant
)
457 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
459 if (set_slant(font_style
, slant
))
460 g_object_notify((GObject
*) font_style
, "slant");
464 * adg_font_style_get_slant:
465 * @font_style: an #AdgFontStyle object
467 * Gets the slant variant of @font_style.
469 * Returns: the slant variant
472 adg_font_style_get_slant(AdgFontStyle
*font_style
)
474 AdgFontStylePrivate
*data
;
476 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
477 CAIRO_FONT_SLANT_NORMAL
);
479 data
= font_style
->data
;
485 * adg_font_style_set_weight:
486 * @font_style: an #AdgFontStyle object
487 * @weight: the new weight
489 * Sets a new weight variant on @font_style.
492 adg_font_style_set_weight(AdgFontStyle
*font_style
,
493 cairo_font_weight_t weight
)
495 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
497 if (set_weight(font_style
, weight
))
498 g_object_notify((GObject
*) font_style
, "weight");
502 * adg_font_style_get_weight:
503 * @font_style: an #AdgFontStyle object
505 * Gets the weight variant of @font_style.
507 * Returns: the weight variant
510 adg_font_style_get_weight(AdgFontStyle
*font_style
)
512 AdgFontStylePrivate
*data
;
514 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
515 CAIRO_FONT_WEIGHT_NORMAL
);
517 data
= font_style
->data
;
523 * adg_font_style_set_size:
524 * @font_style: an #AdgFontStyle object
525 * @size: the new size
527 * Sets a new size (in global space) on @font_style.
530 adg_font_style_set_size(AdgFontStyle
*font_style
, gdouble size
)
532 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
534 if (set_size(font_style
, size
))
535 g_object_notify((GObject
*) font_style
, "size");
539 * adg_font_style_get_size:
540 * @font_style: an #AdgFontStyle object
542 * Gets the size (in global space) of @font_style.
544 * Returns: the size variant
547 adg_font_style_get_size(AdgFontStyle
*font_style
)
549 AdgFontStylePrivate
*data
;
551 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
), 0.);
553 data
= font_style
->data
;
559 * adg_font_style_set_antialias:
560 * @font_style: an #AdgFontStyle object
561 * @antialias: the new antialias mode
563 * Sets a new antialias mode.
566 adg_font_style_set_antialias(AdgFontStyle
*font_style
,
567 cairo_antialias_t antialias
)
569 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
571 if (set_antialias(font_style
, antialias
))
572 g_object_notify((GObject
*) font_style
, "antialias");
576 * adg_font_style_get_antialias:
577 * @font_style: an #AdgFontStyle object
579 * Gets the antialias mode used.
581 * Returns: the requested antialias mode
584 adg_font_style_get_antialias(AdgFontStyle
*font_style
)
586 AdgFontStylePrivate
*data
;
588 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
589 CAIRO_ANTIALIAS_DEFAULT
);
591 data
= font_style
->data
;
593 return data
->antialias
;
597 * adg_font_style_set_subpixel_order:
598 * @font_style: an #AdgFontStyle object
599 * @subpixel_order: the new subpixel order mode
601 * Sets a new subpixel order mode.
604 adg_font_style_set_subpixel_order(AdgFontStyle
*font_style
,
605 cairo_subpixel_order_t subpixel_order
)
607 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
609 if (set_subpixel_order(font_style
, subpixel_order
))
610 g_object_notify((GObject
*) font_style
, "subpixel-order");
614 * adg_font_style_get_subpixel_order:
615 * @font_style: an #AdgFontStyle object
617 * Gets the subpixel order mode used, that is the order of color elements
618 * within each pixel on the display device when rendering with an
619 * antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL.
621 * Returns: the requested subpixel order mode
623 cairo_subpixel_order_t
624 adg_font_style_get_subpixel_order(AdgFontStyle
*font_style
)
626 AdgFontStylePrivate
*data
;
628 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
629 CAIRO_SUBPIXEL_ORDER_DEFAULT
);
631 data
= font_style
->data
;
633 return data
->subpixel_order
;
637 * adg_font_style_set_hint_style:
638 * @font_style: an #AdgFontStyle object
639 * @hint_style: the new hint style mode
641 * Sets a new hint style mode.
644 adg_font_style_set_hint_style(AdgFontStyle
*font_style
,
645 cairo_hint_style_t hint_style
)
647 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
649 if (set_hint_style(font_style
, hint_style
))
650 g_object_notify((GObject
*) font_style
, "hint-style");
654 * adg_font_style_get_hint_style:
655 * @font_style: an #AdgFontStyle object
657 * Gets the hint style mode used, that is how to fit outlines
658 * to the pixel grid in order to improve the appearance of the result.
660 * Returns: the requested hint style mode
663 adg_font_style_get_hint_style(AdgFontStyle
*font_style
)
665 AdgFontStylePrivate
*data
;
667 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
668 CAIRO_HINT_STYLE_DEFAULT
);
670 data
= font_style
->data
;
672 return data
->hint_style
;
676 * adg_font_style_set_hint_metrics:
677 * @font_style: an #AdgFontStyle object
678 * @hint_metrics: the new hint metrics state
680 * Sets a new hint metrics state.
683 adg_font_style_set_hint_metrics(AdgFontStyle
*font_style
,
684 cairo_hint_metrics_t hint_metrics
)
686 g_return_if_fail(ADG_IS_FONT_STYLE(font_style
));
688 if (set_hint_metrics(font_style
, hint_metrics
))
689 g_object_notify((GObject
*) font_style
, "hint-metrics");
693 * adg_font_style_get_hint_metrics:
694 * @font_style: an #AdgFontStyle object
696 * Gets the state on whether to hint font metrics.
698 * Returns: the requested hint metrics state
701 adg_font_style_get_hint_metrics(AdgFontStyle
*font_style
)
703 AdgFontStylePrivate
*data
;
705 g_return_val_if_fail(ADG_IS_FONT_STYLE(font_style
),
706 CAIRO_HINT_METRICS_DEFAULT
);
708 data
= font_style
->data
;
710 return data
->hint_metrics
;
715 apply(AdgStyle
*style
, AdgEntity
*entity
, cairo_t
*cr
)
717 AdgFontStyle
*font_style
;
718 AdgFontStylePrivate
*data
;
720 cairo_scaled_font_t
*font
;
722 font_style
= (AdgFontStyle
*) style
;
723 data
= font_style
->data
;
725 adg_entity_apply_dress(entity
, data
->color_dress
, cr
);
727 cairo_get_matrix(cr
, &ctm
);
728 font
= adg_font_style_get_scaled_font((AdgFontStyle
*) style
, &ctm
);
730 cairo_set_scaled_font(cr
, font
);
734 set_family(AdgFontStyle
*font_style
, const gchar
*family
)
736 AdgFontStylePrivate
*data
= font_style
->data
;
738 if (g_strcmp0(family
, data
->family
) == 0)
741 g_free(data
->family
);
742 data
->family
= g_strdup(family
);
743 unset_face(font_style
);
749 set_slant(AdgFontStyle
*font_style
, cairo_font_slant_t slant
)
751 AdgFontStylePrivate
*data
= font_style
->data
;
753 if (slant
== data
->slant
)
757 unset_face(font_style
);
763 set_weight(AdgFontStyle
*font_style
, cairo_font_weight_t weight
)
765 AdgFontStylePrivate
*data
= font_style
->data
;
767 if (weight
== data
->weight
)
770 data
->weight
= weight
;
771 unset_face(font_style
);
777 set_size(AdgFontStyle
*font_style
, gdouble size
)
779 AdgFontStylePrivate
*data
= font_style
->data
;
781 /* A better approach would be to use the GParamSpec of this property */
782 g_return_val_if_fail(size
>= 0, FALSE
);
784 if (size
== data
->size
)
788 unset_font(font_style
);
794 set_antialias(AdgFontStyle
*font_style
, cairo_antialias_t antialias
)
796 AdgFontStylePrivate
*data
= font_style
->data
;
798 if (antialias
== data
->antialias
)
801 data
->antialias
= antialias
;
802 unset_font(font_style
);
808 set_subpixel_order(AdgFontStyle
*font_style
,
809 cairo_subpixel_order_t subpixel_order
)
811 AdgFontStylePrivate
*data
= font_style
->data
;
813 if (subpixel_order
== data
->subpixel_order
)
816 data
->subpixel_order
= subpixel_order
;
817 unset_font(font_style
);
823 set_hint_style(AdgFontStyle
*font_style
, cairo_hint_style_t hint_style
)
825 AdgFontStylePrivate
*data
= font_style
->data
;
827 if (hint_style
== data
->hint_style
)
830 data
->hint_style
= hint_style
;
831 unset_font(font_style
);
837 set_hint_metrics(AdgFontStyle
*font_style
, cairo_hint_metrics_t hint_metrics
)
839 AdgFontStylePrivate
*data
= font_style
->data
;
841 if (hint_metrics
== data
->hint_metrics
)
844 data
->hint_metrics
= hint_metrics
;
845 unset_font(font_style
);
851 unset_face(AdgFontStyle
*font_style
)
853 AdgFontStylePrivate
*data
= font_style
->data
;
855 if (data
->face
== NULL
)
858 /* Changing the face invalidates the scaled font too */
859 unset_font(font_style
);
861 cairo_font_face_destroy(data
->face
);
866 unset_font(AdgFontStyle
*font_style
)
868 AdgFontStylePrivate
*data
= font_style
->data
;
870 if (data
->font
== NULL
)
873 cairo_scaled_font_destroy(data
->font
);