1 /* Lasem
2  *
3  * Copyright © 2009 Emmanuel Pacaud
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author:
21  * 	Emmanuel Pacaud <emmanuel@gnome.org>
22  */
23 
24 #include <pango/pango-attributes.h>
25 #include <lsmmathmltraits.h>
26 #include <math.h>
27 #include <string.h>
28 #include <stdlib.h>
29 
30 static gboolean
lsm_mathml_boolean_trait_from_string(LsmTrait * abstract_trait,char * string)31 lsm_mathml_boolean_trait_from_string (LsmTrait *abstract_trait, char *string)
32 {
33 	gboolean *value = (gboolean *) abstract_trait;
34 
35 	if (g_strcmp0 (string, "true") == 0) {
36 		*value = TRUE;
37 		return TRUE;
38 	} else if (g_strcmp0 (string, "false") == 0) {
39 		*value = FALSE;
40 		return TRUE;
41 	}
42 
43 	*value = FALSE;
44 	return FALSE;
45 }
46 
47 static char *
lsm_mathml_boolean_trait_to_string(LsmTrait * abstract_trait)48 lsm_mathml_boolean_trait_to_string (LsmTrait *abstract_trait)
49 {
50 	gboolean *value = (gboolean *) abstract_trait;
51 
52 	return g_strdup_printf ("%s", *value ? "true" : "false");
53 }
54 
55 const LsmTraitClass lsm_mathml_boolean_trait_class = {
56 	.size = sizeof (gboolean),
57 	.from_string = lsm_mathml_boolean_trait_from_string,
58 	.to_string = lsm_mathml_boolean_trait_to_string
59 };
60 
61 static gboolean
lsm_mathml_unsigned_trait_from_string(LsmTrait * abstract_trait,char * string)62 lsm_mathml_unsigned_trait_from_string (LsmTrait *abstract_trait, char *string)
63 {
64 	unsigned int *value = (unsigned int *) abstract_trait;
65 	char *end_ptr;
66 
67 	*value = strtol (string, &end_ptr, 10);
68 
69 	return end_ptr != string;
70 }
71 
72 static char *
lsm_mathml_unsigned_trait_to_string(LsmTrait * abstract_trait)73 lsm_mathml_unsigned_trait_to_string (LsmTrait *abstract_trait)
74 {
75 	unsigned int *value = (unsigned int *) abstract_trait;
76 
77 	return g_strdup_printf ("%u", *value);
78 }
79 
80 const LsmTraitClass lsm_mathml_unsigned_trait_class = {
81 	.size = sizeof (unsigned),
82 	.from_string = lsm_mathml_unsigned_trait_from_string,
83 	.to_string = lsm_mathml_unsigned_trait_to_string
84 };
85 
86 static gboolean
lsm_mathml_display_trait_from_string(LsmTrait * abstract_trait,char * string)87 lsm_mathml_display_trait_from_string (LsmTrait *abstract_trait, char *string)
88 {
89 	LsmMathmlDisplay *value = (LsmMathmlDisplay *) abstract_trait;
90 
91 	*value = lsm_mathml_display_from_string (string);
92 
93 	return *value >= 0;
94 }
95 
96 static char *
lsm_mathml_display_trait_to_string(LsmTrait * abstract_trait)97 lsm_mathml_display_trait_to_string (LsmTrait *abstract_trait)
98 {
99 	LsmMathmlDisplay *value = (LsmMathmlDisplay *) abstract_trait;
100 
101 	return g_strdup (lsm_mathml_display_to_string (*value));
102 }
103 
104 const LsmTraitClass lsm_mathml_display_trait_class = {
105 	.size = sizeof (int),
106 	.from_string = lsm_mathml_display_trait_from_string,
107 	.to_string = lsm_mathml_display_trait_to_string
108 };
109 
110 static gboolean
lsm_mathml_mode_trait_from_string(LsmTrait * abstract_trait,char * string)111 lsm_mathml_mode_trait_from_string (LsmTrait *abstract_trait, char *string)
112 {
113 	LsmMathmlMode *value = (LsmMathmlMode *) abstract_trait;
114 
115 	*value = lsm_mathml_mode_from_string (string);
116 
117 	return *value >= 0;
118 }
119 
120 static char *
lsm_mathml_mode_trait_to_string(LsmTrait * abstract_trait)121 lsm_mathml_mode_trait_to_string (LsmTrait *abstract_trait)
122 {
123 	LsmMathmlMode *value = (LsmMathmlMode *) abstract_trait;
124 
125 	return g_strdup (lsm_mathml_mode_to_string (*value));
126 }
127 
128 const LsmTraitClass lsm_mathml_mode_trait_class = {
129 	.size = sizeof (int),
130 	.from_string = lsm_mathml_mode_trait_from_string,
131 	.to_string = lsm_mathml_mode_trait_to_string
132 };
133 
134 static gboolean
lsm_mathml_line_trait_from_string(LsmTrait * abstract_trait,char * string)135 lsm_mathml_line_trait_from_string (LsmTrait *abstract_trait, char *string)
136 {
137 	LsmMathmlLine *value = (LsmMathmlLine *) abstract_trait;
138 
139 	*value = lsm_mathml_line_from_string (string);
140 
141 	return *value >= 0;
142 }
143 
144 static char *
lsm_mathml_line_trait_to_string(LsmTrait * abstract_trait)145 lsm_mathml_line_trait_to_string (LsmTrait *abstract_trait)
146 {
147 	LsmMathmlLine *value = (LsmMathmlLine *) abstract_trait;
148 
149 	return g_strdup (lsm_mathml_line_to_string (*value));
150 }
151 
152 const LsmTraitClass lsm_mathml_line_trait_class = {
153 	.size = sizeof (int),
154 	.from_string = lsm_mathml_line_trait_from_string,
155 	.to_string = lsm_mathml_line_trait_to_string
156 };
157 
158 static gboolean
lsm_mathml_font_style_trait_from_string(LsmTrait * abstract_trait,char * string)159 lsm_mathml_font_style_trait_from_string (LsmTrait *abstract_trait, char *string)
160 {
161 	LsmMathmlFontStyle *value = (LsmMathmlFontStyle *) abstract_trait;
162 
163 	*value = lsm_mathml_font_style_from_string (string);
164 
165 	return *value >= 0;
166 }
167 
168 static char *
lsm_mathml_font_style_trait_to_string(LsmTrait * abstract_trait)169 lsm_mathml_font_style_trait_to_string (LsmTrait *abstract_trait)
170 {
171 	LsmMathmlFontStyle *value = (LsmMathmlFontStyle *) abstract_trait;
172 
173 	return g_strdup (lsm_mathml_font_style_to_string (*value));
174 }
175 
176 const LsmTraitClass lsm_mathml_font_style_trait_class = {
177 	.size = sizeof (int),
178 	.from_string = lsm_mathml_font_style_trait_from_string,
179 	.to_string = lsm_mathml_font_style_trait_to_string
180 };
181 
182 static gboolean
lsm_mathml_font_weight_trait_from_string(LsmTrait * abstract_trait,char * string)183 lsm_mathml_font_weight_trait_from_string (LsmTrait *abstract_trait, char *string)
184 {
185 	LsmMathmlFontWeight *value = (LsmMathmlFontWeight *) abstract_trait;
186 
187 	*value = lsm_mathml_font_weight_from_string (string);
188 
189 	return *value >= 0;
190 }
191 
192 static char *
lsm_mathml_font_weight_trait_to_string(LsmTrait * abstract_trait)193 lsm_mathml_font_weight_trait_to_string (LsmTrait *abstract_trait)
194 {
195 	LsmMathmlFontWeight *value = (LsmMathmlFontWeight *) abstract_trait;
196 
197 	return g_strdup (lsm_mathml_font_weight_to_string (*value));
198 }
199 
200 const LsmTraitClass lsm_mathml_font_weight_trait_class = {
201 	.size = sizeof (int),
202 	.from_string = lsm_mathml_font_weight_trait_from_string,
203 	.to_string = lsm_mathml_font_weight_trait_to_string
204 };
205 
206 static gboolean
lsm_mathml_variant_trait_from_string(LsmTrait * abstract_trait,char * string)207 lsm_mathml_variant_trait_from_string (LsmTrait *abstract_trait, char *string)
208 {
209 	LsmMathmlVariant *value = (LsmMathmlVariant *) abstract_trait;
210 
211 	*value = lsm_mathml_variant_from_string (string);
212 
213 	return *value >= 0;
214 }
215 
216 static char *
lsm_mathml_variant_trait_to_string(LsmTrait * abstract_trait)217 lsm_mathml_variant_trait_to_string (LsmTrait *abstract_trait)
218 {
219 	LsmMathmlVariant *value = (LsmMathmlVariant *) abstract_trait;
220 
221 	return g_strdup (lsm_mathml_variant_to_string (*value));
222 }
223 
224 const LsmTraitClass lsm_mathml_variant_trait_class = {
225 	.size = sizeof (int),
226 	.from_string = lsm_mathml_variant_trait_from_string,
227 	.to_string = lsm_mathml_variant_trait_to_string
228 };
229 
230 static gboolean
lsm_mathml_form_trait_from_string(LsmTrait * abstract_trait,char * string)231 lsm_mathml_form_trait_from_string (LsmTrait *abstract_trait, char *string)
232 {
233 	LsmMathmlForm *value = (LsmMathmlForm *) abstract_trait;
234 
235 	*value = lsm_mathml_form_from_string (string);
236 
237 	return *value >= 0;
238 }
239 
240 static char *
lsm_mathml_form_trait_to_string(LsmTrait * abstract_trait)241 lsm_mathml_form_trait_to_string (LsmTrait *abstract_trait)
242 {
243 	LsmMathmlForm *value = (LsmMathmlForm *) abstract_trait;
244 
245 	return g_strdup (lsm_mathml_form_to_string (*value));
246 }
247 
248 const LsmTraitClass lsm_mathml_form_trait_class = {
249 	.size = sizeof (int),
250 	.from_string = lsm_mathml_form_trait_from_string,
251 	.to_string = lsm_mathml_form_trait_to_string
252 };
253 
254 static gboolean
lsm_mathml_notation_trait_from_string(LsmTrait * abstract_trait,char * string)255 lsm_mathml_notation_trait_from_string (LsmTrait *abstract_trait, char *string)
256 {
257 	LsmMathmlNotation *value = (LsmMathmlNotation *) abstract_trait;
258 
259 	*value = lsm_mathml_notation_from_string (string);
260 
261 	return *value >= 0;
262 }
263 
264 static char *
lsm_mathml_notation_trait_to_string(LsmTrait * abstract_trait)265 lsm_mathml_notation_trait_to_string (LsmTrait *abstract_trait)
266 {
267 	LsmMathmlNotation *value = (LsmMathmlNotation *) abstract_trait;
268 
269 	return g_strdup (lsm_mathml_notation_to_string (*value));
270 }
271 
272 const LsmTraitClass lsm_mathml_notation_trait_class = {
273 	.size = sizeof (int),
274 	.from_string = lsm_mathml_notation_trait_from_string,
275 	.to_string = lsm_mathml_notation_trait_to_string
276 };
277 
278 static gboolean
lsm_mathml_linebreak_trait_from_string(LsmTrait * abstract_trait,char * string)279 lsm_mathml_linebreak_trait_from_string (LsmTrait *abstract_trait, char *string)
280 {
281 	LsmMathmlLinebreak *value = (LsmMathmlLinebreak *) abstract_trait;
282 
283 	*value = lsm_mathml_linebreak_from_string (string);
284 
285 	return *value >= 0;
286 }
287 
288 static char *
lsm_mathml_linebreak_trait_to_string(LsmTrait * abstract_trait)289 lsm_mathml_linebreak_trait_to_string (LsmTrait *abstract_trait)
290 {
291 	LsmMathmlLinebreak *value = (LsmMathmlLinebreak *) abstract_trait;
292 
293 	return g_strdup (lsm_mathml_linebreak_to_string (*value));
294 }
295 
296 const LsmTraitClass lsm_mathml_linebreak_trait_class = {
297 	.size = sizeof (int),
298 	.from_string = lsm_mathml_linebreak_trait_from_string,
299 	.to_string = lsm_mathml_linebreak_trait_to_string
300 };
301 
302 typedef int (*LsmMathmlEnumFromString) (const char *string);
303 typedef char * (*LsmMathmlEnumToString) (unsigned int value);
304 
305 static gboolean
lsm_mathml_enum_list_trait_from_string(LsmMathmlEnumList * enum_list,LsmMathmlEnumFromString from_string,char * string)306 lsm_mathml_enum_list_trait_from_string (LsmMathmlEnumList *enum_list,
307 					LsmMathmlEnumFromString from_string,
308 					char *string)
309 {
310 	char **items;
311 	unsigned int i;
312 	int enum_value;
313 
314 	g_free (enum_list->values);
315 
316 	items = g_strsplit_set (string, " ", -1);
317 	enum_list->n_values = g_strv_length (items);
318 
319 	enum_list->values = g_new (int, enum_list->n_values);
320 	for (i = 0; i < enum_list->n_values; i++) {
321 		enum_value = from_string (items[i]);
322 		if (enum_value < 0) {
323 			g_free (enum_list->values);
324 			enum_list->values = NULL;
325 			enum_list->n_values = 0;
326 			g_strfreev (items);
327 
328 			return FALSE;
329 		}
330 		enum_list->values[i] = enum_value;
331 	}
332 
333 	g_strfreev (items);
334 
335 	return TRUE;
336 }
337 
338 static char *
lsm_mathml_enum_list_trait_to_string(LsmMathmlEnumList * enum_list,LsmMathmlEnumToString to_string)339 lsm_mathml_enum_list_trait_to_string (LsmMathmlEnumList *enum_list,
340 				      LsmMathmlEnumToString to_string)
341 {
342 	return g_strdup ("FIXME");
343 }
344 
345 static void
lsm_mathml_enum_list_trait_init(LsmTrait * abstract_trait,const LsmTrait * abstract_default)346 lsm_mathml_enum_list_trait_init (LsmTrait *abstract_trait,
347 				 const LsmTrait *abstract_default)
348 {
349 	LsmMathmlEnumList *enum_list = (LsmMathmlEnumList *) abstract_trait;
350 	LsmMathmlEnumList *enum_list_defaut = (LsmMathmlEnumList *) abstract_default;
351 
352 	enum_list->n_values = enum_list_defaut->n_values;
353 	if (enum_list->n_values == 0)
354 		enum_list->values = NULL;
355 	else {
356 		enum_list->values = g_new (int, enum_list->n_values);
357 		memcpy (enum_list->values, enum_list_defaut->values, sizeof (int) * enum_list->n_values);
358 	}
359 }
360 
361 void
lsm_mathml_enum_list_init(LsmMathmlEnumList * enum_list,const LsmMathmlEnumList * enum_list_default)362 lsm_mathml_enum_list_init (LsmMathmlEnumList *enum_list, const LsmMathmlEnumList *enum_list_default)
363 {
364 	g_return_if_fail (enum_list != NULL);
365 	g_return_if_fail (enum_list_default != NULL);
366 
367 	lsm_mathml_enum_list_trait_init (enum_list, enum_list_default);
368 }
369 
370 static void
lsm_mathml_enum_list_trait_finalize(LsmTrait * abstract_trait)371 lsm_mathml_enum_list_trait_finalize (LsmTrait *abstract_trait)
372 {
373 	LsmMathmlEnumList *enum_list = (LsmMathmlEnumList *) abstract_trait;
374 
375 	g_free (enum_list->values);
376 	enum_list->values = NULL;
377 	enum_list->n_values = 0;
378 }
379 
380 static gboolean
lsm_mathml_row_align_list_trait_from_string(LsmTrait * abstract_trait,char * string)381 lsm_mathml_row_align_list_trait_from_string (LsmTrait *abstract_trait,
382 					     char *string)
383 {
384 	return lsm_mathml_enum_list_trait_from_string ((LsmMathmlEnumList *) abstract_trait,
385 						       (LsmMathmlEnumFromString) lsm_mathml_row_align_from_string,
386 						       string);
387 }
388 
389 static char *
lsm_mathml_row_align_list_trait_to_string(LsmTrait * abstract_trait)390 lsm_mathml_row_align_list_trait_to_string (LsmTrait *abstract_trait)
391 {
392 	return lsm_mathml_enum_list_trait_to_string ((LsmMathmlEnumList *) abstract_trait,
393 						     (LsmMathmlEnumToString) lsm_mathml_row_align_to_string);
394 }
395 
396 const LsmTraitClass lsm_mathml_row_align_list_trait_class = {
397 	.size = sizeof (LsmMathmlEnumList),
398 	.from_string = lsm_mathml_row_align_list_trait_from_string,
399 	.to_string = lsm_mathml_row_align_list_trait_to_string,
400 	.init = lsm_mathml_enum_list_trait_init,
401 	.finalize = lsm_mathml_enum_list_trait_finalize
402 };
403 
404 static gboolean
lsm_mathml_column_align_list_trait_from_string(LsmTrait * abstract_trait,char * string)405 lsm_mathml_column_align_list_trait_from_string (LsmTrait *abstract_trait,
406 					     char *string)
407 {
408 	return lsm_mathml_enum_list_trait_from_string ((LsmMathmlEnumList *) abstract_trait,
409 						       (LsmMathmlEnumFromString) lsm_mathml_column_align_from_string,
410 						       string);
411 }
412 
413 static char *
lsm_mathml_column_align_list_trait_to_string(LsmTrait * abstract_trait)414 lsm_mathml_column_align_list_trait_to_string (LsmTrait *abstract_trait)
415 {
416 	return lsm_mathml_enum_list_trait_to_string ((LsmMathmlEnumList *) abstract_trait,
417 						     (LsmMathmlEnumToString) lsm_mathml_column_align_to_string);
418 }
419 
420 const LsmTraitClass lsm_mathml_column_align_list_trait_class = {
421 	.size = sizeof (LsmMathmlEnumList),
422 	.from_string = lsm_mathml_column_align_list_trait_from_string,
423 	.to_string = lsm_mathml_column_align_list_trait_to_string,
424 	.init = lsm_mathml_enum_list_trait_init,
425 	.finalize = lsm_mathml_enum_list_trait_finalize
426 };
427 
428 static gboolean
lsm_mathml_line_list_trait_from_string(LsmTrait * abstract_trait,char * string)429 lsm_mathml_line_list_trait_from_string (LsmTrait *abstract_trait,
430 					     char *string)
431 {
432 	return lsm_mathml_enum_list_trait_from_string ((LsmMathmlEnumList *) abstract_trait,
433 						       (LsmMathmlEnumFromString) lsm_mathml_line_from_string,
434 						       string);
435 }
436 
437 static char *
lsm_mathml_line_list_trait_to_string(LsmTrait * abstract_trait)438 lsm_mathml_line_list_trait_to_string (LsmTrait *abstract_trait)
439 {
440 	return lsm_mathml_enum_list_trait_to_string ((LsmMathmlEnumList *) abstract_trait,
441 						     (LsmMathmlEnumToString) lsm_mathml_line_to_string);
442 }
443 
444 const LsmTraitClass lsm_mathml_line_list_trait_class = {
445 	.size = sizeof (LsmMathmlEnumList),
446 	.from_string = lsm_mathml_line_list_trait_from_string,
447 	.to_string = lsm_mathml_line_list_trait_to_string,
448 	.init = lsm_mathml_enum_list_trait_init,
449 	.finalize = lsm_mathml_enum_list_trait_finalize
450 };
451 
452 static gboolean
lsm_mathml_script_level_trait_from_string(LsmTrait * abstract_trait,char * string)453 lsm_mathml_script_level_trait_from_string (LsmTrait *abstract_trait, char *string)
454 {
455 	LsmMathmlScriptLevel *value = (LsmMathmlScriptLevel *) abstract_trait;
456 	char *end_ptr;
457 
458 	value->level = strtol (string, &end_ptr, 10);
459 
460 	if (string[0] == '+')
461 		value->sign = LSM_MATHML_SCRIPT_LEVEL_SIGN_PLUS;
462 	else if (string[0] == '-')
463 		value->sign = LSM_MATHML_SCRIPT_LEVEL_SIGN_MINUS;
464 	else
465 		value->sign = LSM_MATHML_SCRIPT_LEVEL_SIGN_NONE;
466 
467 	return end_ptr != string;
468 }
469 
470 static char *
lsm_mathml_script_level_trait_to_string(LsmTrait * abstract_trait)471 lsm_mathml_script_level_trait_to_string (LsmTrait *abstract_trait)
472 {
473 	LsmMathmlScriptLevel *value = (LsmMathmlScriptLevel *) abstract_trait;
474 
475 	if (value->sign == LSM_MATHML_SCRIPT_LEVEL_SIGN_PLUS)
476 			return g_strdup_printf ("+%d", value->level);
477 
478 	return g_strdup_printf ("%d", value->level);
479 }
480 
481 const LsmTraitClass lsm_mathml_script_level_trait_class = {
482 	.size = sizeof (int),
483 	.from_string = lsm_mathml_script_level_trait_from_string,
484 	.to_string = lsm_mathml_script_level_trait_to_string
485 };
486 
487 static gboolean
lsm_mathml_double_trait_from_string(LsmTrait * abstract_trait,char * string)488 lsm_mathml_double_trait_from_string (LsmTrait *abstract_trait, char *string)
489 {
490 	double *value = (double *) abstract_trait;
491 	char *end_ptr;
492 
493 	*value = g_ascii_strtod (string, &end_ptr);
494 
495 	return end_ptr != string;
496 }
497 
498 static char *
lsm_mathml_double_trait_to_string(LsmTrait * abstract_trait)499 lsm_mathml_double_trait_to_string (LsmTrait *abstract_trait)
500 {
501 	double *value = (double *) abstract_trait;
502 
503 	return g_strdup_printf ("%g", *value);
504 }
505 
506 const LsmTraitClass lsm_mathml_double_trait_class = {
507 	.size = sizeof (double),
508 	.from_string = lsm_mathml_double_trait_from_string,
509 	.to_string = lsm_mathml_double_trait_to_string
510 };
511 
512 static LsmMathmlColor *
lsm_mathml_color_copy(LsmMathmlColor * color)513 lsm_mathml_color_copy (LsmMathmlColor *color)
514 {
515 	LsmMathmlColor *copy;
516 
517 	copy = g_new (LsmMathmlColor, 1);
518 	memcpy (copy, color, sizeof (LsmMathmlColor));
519 
520 	return copy;
521 }
522 
523 GType
lsm_mathml_color_get_type(void)524 lsm_mathml_color_get_type (void)
525 {
526 	static GType our_type = 0;
527 	if (our_type == 0)
528 		our_type = g_boxed_type_register_static
529 			("LsmMathmlColor",
530 			 (GBoxedCopyFunc) lsm_mathml_color_copy,
531 			 (GBoxedFreeFunc) g_free);
532 	return our_type;
533 }
534 
535 static gboolean
lsm_mathml_color_trait_from_string(LsmTrait * abstract_trait,char * string)536 lsm_mathml_color_trait_from_string (LsmTrait *abstract_trait, char *string)
537 {
538 	LsmMathmlColor *color = (LsmMathmlColor *) abstract_trait;
539 	PangoColor pango_color;
540 	gboolean result;
541 
542 	if (strcmp (string, "transparent") == 0) {
543 		color->red = 0.0;
544 		color->green = 0.0;
545 		color->blue = 0.0;
546 		color->alpha = 0.0;
547 
548 		return TRUE;
549 	}
550 
551 	result = pango_color_parse (&pango_color, string);
552 	color->alpha = 1.0;
553 	color->red = pango_color.red / 65535.0;
554 	color->green = pango_color.green / 65535.0;
555 	color->blue = pango_color.blue / 65535.0;
556 
557 	return result;
558 }
559 
560 static char *
lsm_mathml_color_trait_to_string(LsmTrait * abstract_trait)561 lsm_mathml_color_trait_to_string (LsmTrait *abstract_trait)
562 {
563 	LsmMathmlColor *color = (LsmMathmlColor *) abstract_trait;
564 	PangoColor pango_color;
565 
566 	if (color->alpha <= 0.0)
567 		return g_strdup ("transparent");
568 
569 	pango_color.red = ((int) ((double) 0.5 + 65535.0 * color->red));
570 	pango_color.blue = ((int) ((double) 0.5 + 65535.0 * color->blue));
571 	pango_color.green = ((int) ((double) 0.5 + 65535.0 * color->green));
572 
573 	return pango_color_to_string (&pango_color);
574 }
575 
576 const LsmTraitClass lsm_mathml_color_trait_class = {
577 	.size = sizeof (LsmMathmlColor),
578 	.from_string = lsm_mathml_color_trait_from_string,
579 	.to_string = lsm_mathml_color_trait_to_string
580 };
581 
582 static gboolean
lsm_mathml_string_trait_from_string(LsmTrait * abstract_trait,char * string)583 lsm_mathml_string_trait_from_string (LsmTrait *abstract_trait, char *string)
584 {
585 	char **value = (char **) abstract_trait;
586 
587 	g_free (*value);
588 	*value = g_strdup (string);
589 
590 	return TRUE;
591 }
592 
593 static char *
lsm_mathml_string_trait_to_string(LsmTrait * abstract_trait)594 lsm_mathml_string_trait_to_string (LsmTrait *abstract_trait)
595 {
596 	char **value = (char **) abstract_trait;
597 
598 	return g_strdup (*value);
599 }
600 
601 static void
lsm_mathml_string_trait_init(LsmTrait * abstract_trait,const LsmTrait * abstract_default)602 lsm_mathml_string_trait_init (LsmTrait *abstract_trait,
603 			      const LsmTrait *abstract_default)
604 {
605 	char **value = (char **) abstract_trait;
606 	char **default_value = (char **) abstract_default;
607 
608 	*value = g_strdup (*default_value);
609 }
610 
611 static void
lsm_mathml_string_trait_finalize(LsmTrait * abstract_trait)612 lsm_mathml_string_trait_finalize (LsmTrait *abstract_trait)
613 {
614 	char **value = (char **) abstract_trait;
615 
616 	g_free (*value);
617 	*value = NULL;
618 }
619 
620 const LsmTraitClass lsm_mathml_string_trait_class = {
621 	.size = sizeof (char *),
622 	.from_string = lsm_mathml_string_trait_from_string,
623 	.to_string = lsm_mathml_string_trait_to_string,
624 	.init = lsm_mathml_string_trait_init,
625 	.finalize = lsm_mathml_string_trait_finalize
626 };
627 
628 static LsmMathmlLength *
lsm_mathml_length_copy(LsmMathmlLength * length)629 lsm_mathml_length_copy (LsmMathmlLength *length)
630 {
631 	LsmMathmlLength *copy;
632 
633 	copy = g_new (LsmMathmlLength, 1);
634 	memcpy (copy, length, sizeof (LsmMathmlLength));
635 
636 	return copy;
637 }
638 
639 GType
lsm_mathml_length_get_type(void)640 lsm_mathml_length_get_type (void)
641 {
642 	static GType our_type = 0;
643 
644 	if (our_type == 0)
645 		our_type = g_boxed_type_register_static
646 			("LsmMathmlLength",
647 			 (GBoxedCopyFunc) lsm_mathml_length_copy,
648 			 (GBoxedFreeFunc) g_free);
649 	return our_type;
650 }
651 
652 static gboolean
lsm_mathml_length_trait_from_string(LsmTrait * abstract_trait,char * string)653 lsm_mathml_length_trait_from_string (LsmTrait *abstract_trait, char *string)
654 {
655 	LsmMathmlLength *length = (LsmMathmlLength *) abstract_trait;
656 	char *unit_str;
657 
658 	length->value = g_ascii_strtod (string, &unit_str);
659 	length->unit = lsm_mathml_unit_from_string (unit_str);
660 
661 	/* TODO Handle "big", "small", normal" sizes */
662 
663 	return unit_str != string && length->unit >= 0;
664 }
665 
666 static char *
lsm_mathml_length_trait_to_string(LsmTrait * abstract_trait)667 lsm_mathml_length_trait_to_string (LsmTrait *abstract_trait)
668 {
669 	LsmMathmlLength *length = (LsmMathmlLength *) abstract_trait;
670 
671 	return g_strdup_printf ("%g %s", length->value,
672 				lsm_mathml_unit_to_string (length->unit));
673 }
674 
675 const LsmTraitClass lsm_mathml_length_trait_class = {
676 	.size = sizeof (char *),
677 	.from_string = lsm_mathml_length_trait_from_string,
678 	.to_string = lsm_mathml_length_trait_to_string
679 };
680 
681 double
lsm_mathml_length_normalize(const LsmMathmlLength * length,double base,double font_size)682 lsm_mathml_length_normalize (const LsmMathmlLength *length,
683 			     double base,
684 			     double font_size)
685 {
686 	double value;
687 
688 	g_return_val_if_fail (length != NULL, 0.0);
689 
690 	switch (length->unit) {
691 		case LSM_MATHML_UNIT_PX:
692 		case LSM_MATHML_UNIT_PT:
693 			value = length->value;
694 			break;
695 		case LSM_MATHML_UNIT_PC:
696 			value = length->value * 72.0 / 6.0;
697 			break;
698 		case LSM_MATHML_UNIT_CM:
699 			value = length->value * 72.0 / 2.54;
700 			break;
701 		case LSM_MATHML_UNIT_MM:
702 			value = length->value * 72.0 / 25.4;
703 			break;
704 		case LSM_MATHML_UNIT_IN:
705 			value = length->value * 72.0;
706 			break;
707 		case LSM_MATHML_UNIT_EM:
708 			value = length->value * font_size;
709 			break;
710 		case LSM_MATHML_UNIT_EX:
711 			value = length->value * font_size * 0.5;
712 			break;
713 		case LSM_MATHML_UNIT_PERCENT:
714 			value = length->value * base / 100.0;
715 			break;
716 		case LSM_MATHML_UNIT_NONE:
717 			value = length->value * base;
718 			break;
719 		default:
720 			value = 0;
721 	}
722 
723 	return value;
724 }
725 
726 static LsmMathmlSpace *
lsm_mathml_space_copy(LsmMathmlSpace * space)727 lsm_mathml_space_copy (LsmMathmlSpace *space)
728 {
729 	LsmMathmlSpace *copy;
730 
731 	copy = g_new (LsmMathmlSpace, 1);
732 	memcpy (copy, space, sizeof (LsmMathmlSpace));
733 
734 	return copy;
735 }
736 
737 GType
lsm_mathml_space_get_type(void)738 lsm_mathml_space_get_type (void)
739 {
740 	static GType our_type = 0;
741 
742 	if (our_type == 0)
743 		our_type = g_boxed_type_register_static
744 			("LsmMathmlSpace",
745 			 (GBoxedCopyFunc) lsm_mathml_space_copy,
746 			 (GBoxedFreeFunc) g_free);
747 	return our_type;
748 }
749 
750 static gboolean
lsm_mathml_space_trait_from_string(LsmTrait * abstract_trait,char * string)751 lsm_mathml_space_trait_from_string (LsmTrait *abstract_trait, char *string)
752 {
753 	LsmMathmlSpace *space = (LsmMathmlSpace *) abstract_trait;
754 	char *unit_str;
755 
756 	space->name = lsm_mathml_space_name_from_string (string);
757 
758 	if (space->name < 0) {
759 		space->length.value = g_ascii_strtod (string, &unit_str);
760 		space->length.unit = lsm_mathml_unit_from_string (unit_str);
761 
762 		return unit_str != string && space->length.unit >= 0;
763 	}
764 
765 	space->length.value = 0.0;
766 	space->length.unit = LSM_MATHML_UNIT_PX;
767 
768 	return TRUE;
769 }
770 
771 static char *
lsm_mathml_space_trait_to_string(LsmTrait * abstract_trait)772 lsm_mathml_space_trait_to_string (LsmTrait *abstract_trait)
773 {
774 	LsmMathmlSpace *space = (LsmMathmlSpace *) abstract_trait;
775 	const char *string;
776 
777 	string = lsm_mathml_space_name_to_string (space->name);
778 	if (string != NULL)
779 		return g_strdup (string);
780 
781 	return g_strdup_printf ("%g %s", space->length.value,
782 				lsm_mathml_unit_to_string (space->length.unit));
783 }
784 
785 const LsmTraitClass lsm_mathml_space_trait_class = {
786 	.size = sizeof (char *),
787 	.from_string = lsm_mathml_space_trait_from_string,
788 	.to_string = lsm_mathml_space_trait_to_string
789 };
790 
791 static gboolean
lsm_mathml_space_list_trait_from_string(LsmTrait * abstract_trait,char * string)792 lsm_mathml_space_list_trait_from_string (LsmTrait *abstract_trait, char *string)
793 {
794 	LsmMathmlSpaceList *space_list = (LsmMathmlSpaceList *) abstract_trait;
795 	char **items;
796 	unsigned int i;
797 
798 	g_free (space_list->spaces);
799 
800 	items = g_strsplit_set (string, " ", -1);
801 	space_list->n_spaces = g_strv_length (items);
802 
803 	space_list->spaces = g_new (LsmMathmlSpace, space_list->n_spaces);
804 	for (i = 0; i < space_list->n_spaces; i++) {
805 		if (!lsm_mathml_space_trait_from_string (&space_list->spaces[i], items[i])) {
806 			g_free (space_list->spaces);
807 			space_list->spaces = NULL;
808 			space_list->n_spaces = 0;
809 			g_strfreev (items);
810 
811 			return FALSE;
812 		}
813 	}
814 
815 	g_strfreev (items);
816 
817 	return TRUE;
818 }
819 
820 static char *
lsm_mathml_space_list_trait_to_string(LsmTrait * abstract_trait)821 lsm_mathml_space_list_trait_to_string (LsmTrait *abstract_trait)
822 {
823 	return g_strdup ("FIXME");
824 }
825 
826 static void
lsm_mathml_space_list_trait_init(LsmTrait * abstract_trait,const LsmTrait * abstract_default)827 lsm_mathml_space_list_trait_init (LsmTrait *abstract_trait,
828 				  const LsmTrait *abstract_default)
829 {
830 	LsmMathmlSpaceList *space_list = (LsmMathmlSpaceList *) abstract_trait;
831 	LsmMathmlSpaceList *space_list_defaut = (LsmMathmlSpaceList *) abstract_default;
832 
833 	space_list->n_spaces = space_list_defaut->n_spaces;
834 	if (space_list->n_spaces == 0)
835 		space_list->spaces = NULL;
836 	else {
837 		space_list->spaces = g_new (LsmMathmlSpace, space_list->n_spaces);
838 		memcpy (space_list->spaces, space_list_defaut->spaces, sizeof (LsmMathmlSpace) * space_list->n_spaces);
839 	}
840 }
841 
842 static void
lsm_mathml_space_list_trait_finalize(LsmTrait * abstract_trait)843 lsm_mathml_space_list_trait_finalize (LsmTrait *abstract_trait)
844 {
845 	LsmMathmlSpaceList *space_list = (LsmMathmlSpaceList *) abstract_trait;
846 
847 	g_free (space_list->spaces);
848 	space_list->spaces = NULL;
849 	space_list->n_spaces = 0;
850 }
851 
852 void
lsm_mathml_space_list_init(LsmMathmlSpaceList * space_list,const LsmMathmlSpaceList * space_list_default)853 lsm_mathml_space_list_init (LsmMathmlSpaceList *space_list, const LsmMathmlSpaceList *space_list_default)
854 {
855 	g_return_if_fail (space_list != NULL);
856 	g_return_if_fail (space_list_default != NULL);
857 
858 	lsm_mathml_space_list_trait_init (space_list, space_list_default);
859 }
860 
861 const LsmTraitClass lsm_mathml_space_list_trait_class = {
862 	.size = sizeof (LsmMathmlSpaceList),
863 	.from_string = lsm_mathml_space_list_trait_from_string,
864 	.to_string = lsm_mathml_space_list_trait_to_string,
865 	.init = lsm_mathml_space_list_trait_init,
866 	.finalize = lsm_mathml_space_list_trait_finalize
867 };
868