1 /* Fo
2  * fo-property-font-weight.c: 'font-weight' property
3  *
4  * Copyright (C) 2001-2005 Sun Microsystems
5  * Copyright (C) 2007 Menteith Consulting Ltd
6  *
7  * See COPYING for the status of this software.
8  */
9 
10 #include <string.h>
11 #include "fo-utils.h"
12 #include "fo-context.h"
13 #include "datatype/fo-datatype.h"
14 #include "property/fo-property-private.h"
15 #include "property/fo-property-text-property.h"
16 #include "property/fo-property-font-size.h"
17 #include "property/fo-property-font-weight.h"
18 
19 #ifndef FO_FONT_WEIGHT_NORMAL
20 #define FO_FONT_WEIGHT_NORMAL	400
21 #endif	/* !FO_FONT_WEIGHT_NORMAL */
22 
23 #ifndef FO_FONT_WEIGHT_BOLD
24 #define FO_FONT_WEIGHT_BOLD	700
25 #endif	/* !FO_FONT_WEIGHT_BOLD */
26 
27 #ifndef FO_FONT_WEIGHT_STEP
28 #define FO_FONT_WEIGHT_STEP	100
29 #endif	/* !FO_FONT_WEIGHT_STEP */
30 
31 #ifndef FO_FONT_WEIGHT_MAX
32 #define FO_FONT_WEIGHT_MAX	900
33 #endif	/* !FO_FONT_WEIGHT_MAX */
34 
35 #ifndef FO_FONT_WEIGHT_MIN
36 #define FO_FONT_WEIGHT_MIN	100
37 #endif	/* !FO_FONT_WEIGHT_MIN */
38 
39 /* font-weight */
40 /* Inherited: TRUE */
41 /* Shorthand: FALSE */
42 /* normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit */
43 /* Initial value: normal */
44 
45 struct _FoPropertyFontWeight
46 {
47   FoProperty parent_instance;
48 };
49 
50 struct _FoPropertyFontWeightClass
51 {
52   FoPropertyClass parent_class;
53 };
54 
55 static void fo_property_font_weight_init         (FoPropertyFontWeight      *property_font_weight);
56 static void fo_property_font_weight_class_init   (FoPropertyFontWeightClass *klass);
57 static void fo_property_font_weight_finalize     (GObject       *object);
58 static void fo_property_font_weight_text_property_init (FoPropertyTextPropertyIface *iface);
59 
60 static FoDatatype * fo_property_font_weight_resolve_enum (const gchar *token,
61                                                            FoContext   *context,
62                                                            GError     **error);
63 static FoDatatype * fo_property_font_weight_validate (FoDatatype *datatype,
64                                                       FoContext  *context,
65                                                       GError    **error);
66 static PangoAttribute * fo_property_font_weight_new_attr (FoProperty *property);
67 
68 static const gchar class_name[] = "font-weight";
69 static gpointer parent_class;
70 
71 /**
72  * fo_property_font_weight_get_type:
73  *
74  * Register the #FoPropertyFontWeight type if not already registered and
75  * return its #GType value.
76  *
77  * Return value: #GType of #FoPropertyFontWeight.
78  **/
79 GType
fo_property_font_weight_get_type(void)80 fo_property_font_weight_get_type (void)
81 {
82   static GType object_type = 0;
83 
84   if (!object_type)
85     {
86       static const GTypeInfo object_info =
87       {
88         sizeof (FoPropertyFontWeightClass),
89         NULL,           /* base_init */
90         NULL,           /* base_finalize */
91         (GClassInitFunc) fo_property_font_weight_class_init,
92         NULL,           /* class_finalize */
93         NULL,           /* class_data */
94         sizeof (FoPropertyFontWeight),
95         0,              /* n_preallocs */
96         (GInstanceInitFunc) fo_property_font_weight_init,
97 	NULL		/* value_table */
98       };
99 
100       static const GInterfaceInfo fo_property_text_property_info =
101       {
102 	(GInterfaceInitFunc) fo_property_font_weight_text_property_init, /* interface_init */
103         NULL,
104         NULL
105       };
106 
107       object_type = g_type_register_static (FO_TYPE_PROPERTY,
108                                             class_name,
109                                             &object_info, 0);
110 
111       g_type_add_interface_static (object_type,
112                                    FO_TYPE_PROPERTY_TEXT_PROPERTY,
113                                    &fo_property_text_property_info);
114     }
115 
116   return object_type;
117 }
118 
119 /**
120  * fo_property_font_weight_init:
121  * @font_weight: #FoPropertyFontWeight object to initialise.
122  *
123  * Implements #GInstanceInitFunc for #FoPropertyFontWeight.
124  **/
125 void
fo_property_font_weight_init(FoPropertyFontWeight * font_weight)126 fo_property_font_weight_init (FoPropertyFontWeight *font_weight)
127 {
128   FO_PROPERTY (font_weight)->value =
129     g_object_ref (fo_integer_new_with_value (FO_FONT_WEIGHT_NORMAL));
130 }
131 
132 /**
133  * fo_property_font_weight_class_init:
134  * @klass: #FoPropertyFontWeightClass object to initialise.
135  *
136  * Implements #GClassInitFunc for #FoPropertyFontWeightClass.
137  **/
138 void
fo_property_font_weight_class_init(FoPropertyFontWeightClass * klass)139 fo_property_font_weight_class_init (FoPropertyFontWeightClass *klass)
140 {
141   GObjectClass *object_class = G_OBJECT_CLASS (klass);
142   FoPropertyClass *property_class = FO_PROPERTY_CLASS (klass);
143 
144   parent_class = g_type_class_peek_parent (klass);
145 
146   object_class->finalize = fo_property_font_weight_finalize;
147 
148   property_class->is_inherited = TRUE;
149   property_class->is_shorthand = FALSE;
150   property_class->resolve_enum =
151     fo_property_font_weight_resolve_enum;
152   property_class->validate =
153     fo_property_font_weight_validate;
154   property_class->get_initial =
155     fo_property_font_weight_get_initial;
156 }
157 
158 /**
159  * fo_property_font_weight_finalize:
160  * @object: #FoPropertyFontWeight object to finalize.
161  *
162  * Implements #GObjectFinalizeFunc for #FoPropertyFontWeight.
163  **/
164 void
fo_property_font_weight_finalize(GObject * object)165 fo_property_font_weight_finalize (GObject *object)
166 {
167   FoPropertyFontWeight *font_weight;
168 
169   font_weight = FO_PROPERTY_FONT_WEIGHT (object);
170 
171   G_OBJECT_CLASS (parent_class)->finalize (object);
172 }
173 
174 /**
175  * fo_property_font_weight_text_property_init:
176  * @iface: #FoPropertyTextPropertyIFace structure for this class.
177  *
178  * Initialize #FoPropertyTextPropertyIface interface for this class.
179  **/
180 void
fo_property_font_weight_text_property_init(FoPropertyTextPropertyIface * iface)181 fo_property_font_weight_text_property_init (FoPropertyTextPropertyIface *iface)
182 {
183   iface->new_attr = fo_property_font_weight_new_attr;
184 }
185 
186 /**
187  * fo_property_font_weight_new:
188  *
189  * Creates a new #FoPropertyFontWeight initialized to default value.
190  *
191  * Return value: the new #FoPropertyFontWeight.
192  **/
193 FoProperty*
fo_property_font_weight_new(void)194 fo_property_font_weight_new (void)
195 {
196   FoProperty* font_weight;
197 
198   font_weight =
199     FO_PROPERTY (g_object_new (fo_property_font_weight_get_type (),
200                                NULL));
201 
202   return font_weight;
203 }
204 
205 /**
206  * fo_property_font_weight_resolve_enum:
207  * @token:   Token from the XML attribute value to be evaluated as an
208  *           enumeration token.
209  * @context: #FoContext object from which to possibly inherit values.
210  * @error:   Information about any error that has occurred.
211  *
212  * Compare @token against the enumeration tokens that are valid for the
213  * current FO property.  If @token is valid, returns either an #FoEnum datatype
214  * representing the enumeration token or a different datatype representing
215  * the enumeration token's resolved value.  If @token is not valid,
216  * sets @error and returns NULL.
217  *
218  * Return value: Resolved enumeration value or NULL.
219  **/
220 FoDatatype*
fo_property_font_weight_resolve_enum(const gchar * token,FoContext * context,GError ** error)221 fo_property_font_weight_resolve_enum (const gchar *token,
222                                       FoContext   *context,
223                                       GError     **error)
224 {
225   gint old_font_weight_value;
226 
227   g_return_val_if_fail (token != NULL, NULL);
228   g_return_val_if_fail (FO_IS_CONTEXT (context), NULL);
229   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
230 
231   if (strcmp (token, "normal") == 0)
232     {
233       return fo_integer_new_with_value (FO_FONT_WEIGHT_NORMAL);
234     }
235   else if (strcmp (token, "bold") == 0)
236     {
237       return fo_integer_new_with_value (FO_FONT_WEIGHT_BOLD);
238     }
239   else if (strcmp (token, "bolder") == 0)
240     {
241       /* FIXME: Redo with fo_datatype_max(), etc. */
242       old_font_weight_value =
243 	fo_integer_get_value (fo_property_get_value (fo_context_get_font_weight (context)));
244 
245       return fo_integer_new_with_value (MIN (old_font_weight_value + FO_FONT_WEIGHT_STEP,
246 					     FO_FONT_WEIGHT_MAX));
247     }
248   else if (strcmp (token, "lighter") == 0)
249     {
250       old_font_weight_value =
251 	fo_integer_get_value (fo_property_get_value (fo_context_get_font_weight (context)));
252 
253       return fo_integer_new_with_value (MAX (old_font_weight_value - FO_FONT_WEIGHT_STEP,
254 					     FO_FONT_WEIGHT_MIN));
255     }
256   else
257     {
258       g_set_error (error,
259 		   FO_FO_ERROR,
260 		   FO_FO_ERROR_ENUMERATION_TOKEN,
261 		   _(fo_fo_error_messages[FO_FO_ERROR_ENUMERATION_TOKEN]),
262 		   class_name,
263 		   token);
264       return NULL;
265     }
266 }
267 
268 /**
269  * fo_property_font_weight_validate:
270  * @datatype: #FoDatatype to be validated against allowed datatypes and
271  *            values for current property.
272  * @context:  #FoContext object from which to possibly inherit values.
273  * @error:    Information about any error that has occurred.
274  *
275  * Validates @datatype against allowed values.  Returns @datatype, a
276  * replacement datatype value, or NULL if validation failed.
277  *
278  * Return value: Valid datatype value or NULL.
279  **/
280 FoDatatype*
fo_property_font_weight_validate(FoDatatype * datatype,FoContext * context,GError ** error)281 fo_property_font_weight_validate (FoDatatype *datatype,
282                                   FoContext  *context,
283                                   GError    **error)
284 {
285   FoDatatype *new_datatype;
286   GError     *tmp_error = NULL;
287   gchar      *token;
288   gint        int_value;
289   gfloat      float_value;
290 
291   g_return_val_if_fail (datatype != NULL, NULL);
292   g_return_val_if_fail (FO_IS_DATATYPE (datatype), NULL);
293   g_return_val_if_fail (context != NULL, NULL);
294   g_return_val_if_fail (FO_IS_CONTEXT (context), NULL);
295   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
296 
297   if (FO_IS_ENUM (datatype))
298     {
299       FoEnumEnum value = fo_enum_get_value (datatype);
300 
301       if (value == FO_ENUM_ENUM_NORMAL)
302 	{
303 	  return fo_integer_new_with_value (FO_FONT_WEIGHT_NORMAL);
304 	}
305       else if (value == FO_ENUM_ENUM_BOLD)
306 	{
307 	  return fo_integer_new_with_value (FO_FONT_WEIGHT_BOLD);
308 	}
309       else if ((value == FO_ENUM_ENUM_BOLDER) ||
310 	       (value == FO_ENUM_ENUM_LIGHTER))
311 	{
312 	  return datatype;
313 	}
314       else if (value == FO_ENUM_ENUM_100)
315 	{
316 	  return fo_integer_new_with_value (100);
317 	}
318       else if (value == FO_ENUM_ENUM_200)
319 	{
320 	  return fo_integer_new_with_value (200);
321 	}
322       else if (value == FO_ENUM_ENUM_300)
323 	{
324 	  return fo_integer_new_with_value (300);
325 	}
326       else if (value == FO_ENUM_ENUM_400)
327 	{
328 	  return fo_integer_new_with_value (400);
329 	}
330       else if (value == FO_ENUM_ENUM_500)
331 	{
332 	  return fo_integer_new_with_value (500);
333 	}
334       else if (value == FO_ENUM_ENUM_600)
335 	{
336 	  return fo_integer_new_with_value (600);
337 	}
338       else if (value == FO_ENUM_ENUM_700)
339 	{
340 	  return fo_integer_new_with_value (700);
341 	}
342       else if (value == FO_ENUM_ENUM_800)
343 	{
344 	  return fo_integer_new_with_value (800);
345 	}
346       else if (value == FO_ENUM_ENUM_900)
347 	{
348 	  return fo_integer_new_with_value (900);
349 	}
350       else
351 	{
352 	  gchar *datatype_sprintf = fo_object_sprintf (datatype);
353 
354 	  g_set_error (error,
355 		       FO_FO_ERROR,
356 		       FO_FO_ERROR_ENUMERATION_TOKEN,
357 		       _(fo_fo_error_messages[FO_FO_ERROR_ENUMERATION_TOKEN]),
358 		       class_name,
359 		       datatype_sprintf,
360 		       g_type_name (G_TYPE_FROM_INSTANCE (datatype)));
361 
362 	  g_object_unref (datatype);
363 
364 	  g_free (datatype_sprintf);
365 
366 	  return NULL;
367 	}
368     }
369   else if (FO_IS_STRING (datatype))
370     {
371       token = fo_string_get_value (datatype);
372 
373       new_datatype =
374         fo_property_font_weight_resolve_enum (token, context, &tmp_error);
375 
376       g_object_unref (datatype);
377 
378       fo_propagate_and_return_val_if_error (error, tmp_error, NULL);
379 
380       return new_datatype;
381     }
382   else if (FO_IS_NAME (datatype))
383     {
384       token = fo_name_get_value (datatype);
385 
386       new_datatype =
387         fo_property_font_weight_resolve_enum (token, context, &tmp_error);
388 
389       g_object_unref (datatype);
390 
391       fo_propagate_and_return_val_if_error (error, tmp_error, NULL);
392 
393       return new_datatype;
394     }
395   else if (FO_IS_NUMBER (datatype))
396     {
397       float_value = fo_number_get_value (datatype);
398 
399       if ((float_value == 100) || (float_value == 200) ||
400 	  (float_value == 300) || (float_value == 400) ||
401 	  (float_value == 500) || (float_value == 600) ||
402 	  (float_value == 700) || (float_value == 800) ||
403 	  (float_value == 900))
404 	{
405 	  new_datatype = fo_integer_new_with_value ((int) float_value);
406 	  g_object_unref (datatype);
407 
408 	  return new_datatype;
409 	}
410       else
411 	{
412 	  g_warning ("Incorrect font-weight: %g", float_value);
413 
414 	  int_value = (int) float_value / 100;
415 
416 	  int_value = CLAMP (int_value, 1, 9) * 100;
417 
418 	  new_datatype = fo_integer_new_with_value (int_value);
419 
420 	  g_object_unref (datatype);
421 
422 	  return new_datatype;
423 	}
424     }
425   else if (FO_IS_INTEGER (datatype))
426     {
427       int_value = fo_integer_get_value (datatype);
428 
429       if ((int_value == 100) || (int_value == 200) ||
430 	  (int_value == 300) || (int_value == 400) ||
431 	  (int_value == 500) || (int_value == 600) ||
432 	  (int_value == 700) || (int_value == 800) ||
433 	  (int_value == 900))
434 	{
435 	  return datatype;
436 	}
437       else
438 	{
439 	  g_warning ("Incorrect font-weight: %d", int_value);
440 
441 	  int_value = CLAMP (int_value / 100, 1, 9) * 100;
442 
443 	  new_datatype = fo_integer_new_with_value (int_value);
444 
445 	  g_object_unref (datatype);
446 
447 	  return new_datatype;
448 	}
449     }
450   else
451     {
452       gchar *datatype_sprintf = fo_object_sprintf (datatype);
453 
454       g_set_error (error,
455 		   FO_FO_ERROR,
456 		   FO_FO_ERROR_DATATYPE,
457 		   _(fo_fo_error_messages[FO_FO_ERROR_DATATYPE]),
458 		   class_name,
459 		   datatype_sprintf,
460 		   g_type_name (G_TYPE_FROM_INSTANCE (datatype)));
461 
462       g_object_unref (datatype);
463 
464       g_free (datatype_sprintf);
465 
466       return NULL;
467     }
468 }
469 
470 /**
471  * fo_property_font_weight_get_initial:
472  *
473  * Get an instance of the property with the correct initial value.
474  *
475  * Return value: An instance of the property.
476  **/
477 FoProperty*
fo_property_font_weight_get_initial(void)478 fo_property_font_weight_get_initial (void)
479 {
480   static FoProperty *font_weight = NULL;
481 
482   if (font_weight == NULL)
483     {
484       font_weight =
485 	fo_property_font_weight_new ();
486     }
487 
488   return font_weight;
489 }
490 
491 /**
492  * fo_property_font_weight_new_attr:
493  * @property: #FoProperty from which to create a #PangoAttribute.
494  *
495  * Makes a new #PangoAttribute representing the current property.
496  *
497  * Return value: New #PangoAttribute.
498  **/
499 PangoAttribute*
fo_property_font_weight_new_attr(FoProperty * property)500 fo_property_font_weight_new_attr (FoProperty *property)
501 {
502   gint pango_font_weight;
503 
504   g_return_val_if_fail (FO_IS_PROPERTY_FONT_WEIGHT (property), NULL);
505 
506   pango_font_weight =
507     fo_integer_get_value (property->value);
508 
509   return pango_attr_weight_new (pango_font_weight);
510 }
511