1 /* "a -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*  This file is part of the GtkHTML library.
3  *
4  *  Copyright (C) 2002, Ximian Inc.
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20 */
21 
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include "htmlstyle.h"
26 
27 /* Color handling.  */
28 gboolean
html_parse_color(const gchar * text,GdkColor * color)29 html_parse_color (const gchar *text,
30                   GdkColor *color)
31 {
32 	gchar c[8];
33 	gint  len = strlen (text);
34 
35 	if (gdk_color_parse (text, color)) {
36 		return TRUE;
37 	} else {
38 		/* standard color names for HTML 4.01 */
39 		static struct html_color_table {
40 			const gchar *name, *value;
41 		} color_tab[] = {
42 			{ "black", "#000000" },
43 			{ "silver", "#C0C0C0" },
44 			{ "gray", "#808080" },
45 			{ "white", "#FFFFFF" },
46 			{ "maroon", "#800000" },
47 			{ "red", "#FF0000" },
48 			{ "purple", "#800080" },
49 			{ "fuchsia", "#FF00FF" },
50 			{ "green", "#008000" },
51 			{ "lime", "#00FF00" },
52 			{ "olive", "#808000" },
53 			{ "yellow", "#FFFF00" },
54 			{ "navy", "#000080" },
55 			{ "blue", "#0000FF" },
56 			{ "teal", "#008080" },
57 			{ "aqua", "#00FFFF" }
58 		};
59 
60 		gint i;
61 		for (i = 0; i < G_N_ELEMENTS (color_tab); i++) {
62 			if (g_ascii_strcasecmp (color_tab[i].name, text) == 0)
63 				return gdk_color_parse (color_tab[i].value, color);
64 		}
65 	}
66 
67 	c[7] = 0;
68 	if (*text != '#') {
69 		c[0] = '#';
70 		strncpy (c + 1, text, 6);
71 		len++;
72 	} else {
73 		strncpy (c, text, MIN (7, len));
74 	}
75 
76 	if (len < 7)
77 		memset (c + len, '\0', 7 - len);
78 
79 	return gdk_color_parse (c, color);
80 }
81 
82 static HTMLLength *
parse_length(gchar * str)83 parse_length (gchar *str) {
84         gchar *cur = str;
85         HTMLLength *len;
86 
87         len = g_new0 (HTMLLength,
88               1);
89 
90         if (!str)
91                 return len;
92 
93 	/* g_warning ("begin \"%s\"", *str); */
94 
95         while (isspace (*cur)) cur++;
96 
97         len->val = atoi (cur);
98         len->type = HTML_LENGTH_TYPE_PIXELS;
99 
100         while (isdigit (*cur) || *cur == '-') cur++;
101 
102         switch (*cur) {
103         case '*':
104                 if (len->val == 0)
105                         len->val = 1;
106                 len->type = HTML_LENGTH_TYPE_FRACTION;
107                 cur++;
108                 break;
109         case '%':
110                 len->type = HTML_LENGTH_TYPE_PERCENT;
111                 cur++;
112                 break;
113         }
114 
115         if (cur <= str) {
116                 g_free (len);
117                 return NULL;
118         }
119 
120 	/* g_warning ("length len->val=%d, len->type=%d", len->val, len->type); */
121 
122         return len;
123 }
124 
125 HTMLStyle *
html_style_new(void)126 html_style_new (void)
127 {
128 	HTMLStyle *style = g_new0 (HTMLStyle, 1);
129 
130 	style->display = DISPLAY_NONE;
131 
132 	style->color = NULL;
133 	style->mask = 0;
134 	style->settings = 0;
135 
136 	/* BLOCK */
137 	style->text_align = HTML_HALIGN_NONE;
138 	style->clear = HTML_CLEAR_NONE;
139 
140 	style->text_valign = HTML_VALIGN_NONE;
141 
142 	return style;
143 }
144 
145 void
html_style_free(HTMLStyle * style)146 html_style_free (HTMLStyle *style)
147 {
148 	if (!style)
149 		return;
150 
151 	g_free (style->face);
152 	g_free (style->bg_image);
153 	g_free (style->width);
154 	g_free (style->height);
155 
156 	if (style->color)
157 		html_color_unref (style->color);
158 
159 	if (style->bg_color)
160 		html_color_unref (style->bg_color);
161 
162 	if (style->border_color)
163 		html_color_unref (style->border_color);
164 
165 	g_free (style);
166 }
167 
168 HTMLStyle *
html_style_add_color(HTMLStyle * style,HTMLColor * color)169 html_style_add_color (HTMLStyle *style,
170                       HTMLColor *color)
171 {
172 	HTMLColor *old;
173 
174 	if (!style)
175 		style = html_style_new ();
176 
177 	old = style->color;
178 
179 	style->color = color;
180 
181 	if (color)
182 		html_color_ref (color);
183 
184 	if (old)
185 		html_color_unref (old);
186 
187 	return style;
188 }
189 
190 HTMLStyle *
html_style_unset_decoration(HTMLStyle * style,GtkHTMLFontStyle font_style)191 html_style_unset_decoration (HTMLStyle *style,
192                              GtkHTMLFontStyle font_style)
193 {
194 	if (!style)
195 		style = html_style_new ();
196 
197 	font_style &= ~GTK_HTML_FONT_STYLE_SIZE_MASK;
198 	style->mask |= font_style;
199 	style->settings &= ~font_style;
200 
201 	return style;
202 }
203 
204 HTMLStyle *
html_style_set_decoration(HTMLStyle * style,GtkHTMLFontStyle font_style)205 html_style_set_decoration (HTMLStyle *style,
206                            GtkHTMLFontStyle font_style)
207 {
208 	if (!style)
209 		style = html_style_new ();
210 
211 	font_style &= ~GTK_HTML_FONT_STYLE_SIZE_MASK;
212 	style->mask |= font_style;
213 	style->settings |= font_style;
214 
215 	return style;
216 }
217 
218 HTMLStyle *
html_style_set_font_size(HTMLStyle * style,GtkHTMLFontStyle font_style)219 html_style_set_font_size (HTMLStyle *style,
220                           GtkHTMLFontStyle font_style)
221 {
222 	if (!style)
223 		style = html_style_new ();
224 
225 	font_style &= GTK_HTML_FONT_STYLE_SIZE_MASK;
226 	style->mask |= GTK_HTML_FONT_STYLE_SIZE_MASK;
227 	style->settings |= font_style;
228 
229 	return style;
230 }
231 
232 HTMLStyle *
html_style_add_font_face(HTMLStyle * style,const HTMLFontFace * face)233 html_style_add_font_face (HTMLStyle *style,
234                           const HTMLFontFace *face)
235 {
236 	if (!style)
237 		style = html_style_new ();
238 
239 	g_free (style->face);
240 	style->face = g_strdup (face);
241 
242 	return style;
243 }
244 
245 HTMLStyle *
html_style_add_text_align(HTMLStyle * style,HTMLHAlignType type)246 html_style_add_text_align (HTMLStyle *style,
247                            HTMLHAlignType type)
248 {
249 	if (!style)
250 		style = html_style_new ();
251 
252 	style->text_align = type;
253 
254 	return style;
255 }
256 
257 HTMLStyle *
html_style_add_text_valign(HTMLStyle * style,HTMLVAlignType type)258 html_style_add_text_valign (HTMLStyle *style,
259                             HTMLVAlignType type)
260 {
261 	if (!style)
262 		style = html_style_new ();
263 
264 	style->text_valign = type;
265 
266 	return style;
267 }
268 
269 HTMLStyle *
html_style_add_background_color(HTMLStyle * style,HTMLColor * color)270 html_style_add_background_color (HTMLStyle *style,
271                                  HTMLColor *color)
272 {
273 	HTMLColor *old;
274 
275 	if (!style)
276 		style = html_style_new ();
277 
278 	old = style->bg_color;
279 
280 	style->bg_color = color;
281 
282 	if (color)
283 		html_color_ref (color);
284 
285 	if (old)
286 		html_color_unref (old);
287 
288 	return style;
289 }
290 
291 HTMLStyle *
html_style_set_display(HTMLStyle * style,HTMLDisplayType display)292 html_style_set_display (HTMLStyle *style,
293                         HTMLDisplayType display)
294 {
295 	if (!style)
296 		style = html_style_new ();
297 
298 	style->display = display;
299 
300 	return style;
301 }
302 
303 HTMLStyle *
html_style_set_clear(HTMLStyle * style,HTMLClearType clear)304 html_style_set_clear (HTMLStyle *style,
305                       HTMLClearType clear)
306 {
307 	if (!style)
308 		style = html_style_new ();
309 
310 	style->clear = clear;
311 
312 	return style;
313 }
314 
315 HTMLStyle *
html_style_add_width(HTMLStyle * style,gchar * len)316 html_style_add_width (HTMLStyle *style,
317                       gchar *len)
318 {
319 	if (!style)
320 		style = html_style_new ();
321 
322 	g_free (style->width);
323 
324 	style->width = parse_length (len);
325 
326 	return style;
327 }
328 
329 HTMLStyle *
html_style_add_height(HTMLStyle * style,gchar * len)330 html_style_add_height (HTMLStyle *style,
331                        gchar *len)
332 {
333 	if (!style)
334 		style = html_style_new ();
335 
336 	g_free (style->height);
337 
338 	style->height = parse_length (len);
339 
340 	return style;
341 }
342 
343 HTMLStyle *
html_style_add_background_image(HTMLStyle * style,const gchar * url)344 html_style_add_background_image (HTMLStyle *style,
345                                  const gchar *url)
346 {
347 	if (!style)
348 		style = html_style_new ();
349 
350 	g_free (style->bg_image);
351 	style->bg_image = g_strdup (url);
352 
353 	return style;
354 }
355 
356 HTMLStyle *
html_style_set_border_style(HTMLStyle * style,HTMLBorderStyle bstyle)357 html_style_set_border_style (HTMLStyle *style,
358                              HTMLBorderStyle bstyle)
359 {
360 	if (!style)
361 		style = html_style_new ();
362 
363 	style->border_style = bstyle;
364 
365 	return style;
366 }
367 
368 HTMLStyle *
html_style_set_border_width(HTMLStyle * style,gint width)369 html_style_set_border_width (HTMLStyle *style,
370                              gint width)
371 {
372 	if (!style)
373 		style = html_style_new ();
374 
375 	style->border_width = width;
376 
377 	return style;
378 }
379 
380 HTMLStyle *
html_style_set_padding(HTMLStyle * style,gint padding)381 html_style_set_padding (HTMLStyle *style,
382                         gint padding)
383 {
384 	if (!style)
385 		style = html_style_new ();
386 
387 	style->padding = padding;
388 
389 	return style;
390 }
391 
392 HTMLStyle *
html_style_set_border_color(HTMLStyle * style,HTMLColor * color)393 html_style_set_border_color (HTMLStyle *style,
394                              HTMLColor *color)
395 {
396 	HTMLColor *old;
397 
398 	if (!style)
399 		style = html_style_new ();
400 
401 	old = style->border_color;
402 
403 	style->border_color = color;
404 
405 	if (color)
406 		html_color_ref (color);
407 
408 	if (old)
409 		html_color_unref (old);
410 
411 	return style;
412 }
413 
414 static HTMLStyle *
parse_border_style(HTMLStyle * style,gchar * value)415 parse_border_style (HTMLStyle *style,
416                     gchar *value)
417 {
418 	while (isspace (*value))
419 		value++;
420 
421 	if (!g_ascii_strcasecmp (value, "solid"))
422 		style = html_style_set_border_style (style, HTML_BORDER_SOLID);
423 	else if (!g_ascii_strcasecmp (value, "inset"))
424 		style = html_style_set_border_style (style, HTML_BORDER_INSET);
425 
426 	return style;
427 }
428 
429 static HTMLStyle *
parse_border_color(HTMLStyle * style,gchar * value)430 parse_border_color (HTMLStyle *style,
431                     gchar *value)
432 {
433 	GdkColor color;
434 
435 	if (html_parse_color (value, &color)) {
436 		HTMLColor *hc = html_color_new_from_gdk_color (&color);
437 		style = html_style_set_border_color (style, hc);
438 		html_color_unref (hc);
439 	}
440 
441 	return style;
442 }
443 
444 static HTMLStyle *
parse_border_width(HTMLStyle * style,gchar * value)445 parse_border_width (HTMLStyle *style,
446                     gchar *value)
447 {
448 	while (isspace (*value))
449 		value++;
450 
451 	if (!g_ascii_strcasecmp (value, "thin"))
452 		style = html_style_set_border_width (style, 1);
453 	else if (!g_ascii_strcasecmp (value, "medium"))
454 		style = html_style_set_border_width (style, 2);
455 	else if (!g_ascii_strcasecmp (value, "thick"))
456 		style = html_style_set_border_width (style, 5);
457 	else if (isdigit (*value))
458 		style = html_style_set_border_width (style, atoi (value));
459 
460 	return style;
461 }
462 
463 static HTMLStyle *
parse_border(HTMLStyle * style,gchar * value)464 parse_border (HTMLStyle *style,
465               gchar *value)
466 {
467 	while (value && *value) {
468 		gchar *next;
469 		gint modified;
470 		gchar orig = 0;
471 
472 		while (isspace (*value))
473 			value++;
474 
475 		next = value;
476 		while (*next && !isspace (*next))
477 			next++;
478 		if (*next) {
479 			orig = *next;
480 			*next = 0;
481 			modified = 1;
482 		} else
483 			modified = 0;
484 
485 		style = parse_border_style (style, value);
486 		style = parse_border_color (style, value);
487 		style = parse_border_width (style, value);
488 
489 		if (modified) {
490 			*next = orig;
491 			next++;
492 		}
493 
494 		value = next;
495 	}
496 
497 	return style;
498 }
499 
500 HTMLStyle *
html_style_add_attribute(HTMLStyle * style,const gchar * attr)501 html_style_add_attribute (HTMLStyle *style,
502                           const gchar *attr)
503 {
504 	gchar **prop;
505 
506 	prop = g_strsplit (attr, ";", 100);
507 	if (prop) {
508 		gint i;
509 		for (i = 0; prop[i]; i++) {
510 			gchar *text;
511 
512 			text = g_strstrip (prop[i]);
513 			if (!g_ascii_strncasecmp ("color: ", text, 7)) {
514 				GdkColor color;
515 
516 				if (html_parse_color (g_strstrip (text + 7), &color)) {
517 					HTMLColor *hc = html_color_new_from_gdk_color (&color);
518 					style = html_style_add_color (style, hc);
519 					html_color_unref (hc);
520 
521 				}
522 			} else if (!g_ascii_strncasecmp ("background: ", text, 12)) {
523 				GdkColor color;
524 
525 				if (html_parse_color (text + 12, &color)) {
526 					HTMLColor *hc = html_color_new_from_gdk_color (&color);
527 					style = html_style_add_background_color (style, hc);
528 					html_color_unref (hc);
529 				}
530 			} else if (!g_ascii_strncasecmp ("background-color: ", text, 18)) {
531 				GdkColor color;
532 
533 				if (html_parse_color (text + 18, &color)) {
534 					HTMLColor *hc = html_color_new_from_gdk_color (&color);
535 					style = html_style_add_background_color (style, hc);
536 					html_color_unref (hc);
537 				}
538 			} else if (!g_ascii_strncasecmp ("background-image: ", text, 18)) {
539 				style = html_style_add_background_image (style, text + 18);
540 
541 			} else if (!g_ascii_strncasecmp ("border: ", text, 8)) {
542 				style = parse_border (style, text + 8);
543 			} else if (!g_ascii_strncasecmp ("border-style: ", text, 14)) {
544 				style = parse_border_style (style, text + 14);
545 			} else if (!g_ascii_strncasecmp ("border-color: ", text, 14)) {
546 				style = parse_border_color (style, text + 14);
547 			} else if (!g_ascii_strncasecmp ("border-width: ", text, 14)) {
548 				style = parse_border_width (style, text + 14);
549 			} else if (!g_ascii_strncasecmp ("padding: ", text, 9)) {
550 				gchar *value = text + 9;
551 
552 				style = html_style_set_padding (style, atoi (value));
553 			} else if (!g_ascii_strncasecmp ("white-space: ", text, 13)) {
554 				/* normal, pre, nowrap, pre-wrap, pre-line, inherit  */
555 				/*
556 				if (!g_ascii_strcasecmp ("normal", text + 13)) {
557 					style = html_style_set_white_space (style, HTML_WHITE_SPACE_NORMAL);
558 				} else if (!g_ascii_strcasecmp ("pre", text + 13)) {
559 					style = html_style_set_white_space (style, HTML_WHITE_SPACE_PRE);
560 				} else if (!g_ascii_strcasecmp ("nowrap", text + 13)) {
561 					style = html_style_set_white_space (style, HTML_WHITE_SPACE_NOWRAP);
562 				} else if (!g_ascii_strcasecmp ("pre-wrap", text + 13)) {
563 					style = html_style_set_white_space (style, HTML_WHITE_SPACE_PRE_WRAP);
564 				} else if (!g_ascii_strcasecmp ("pre-line", text + 13)) {
565 					style = html_style_set_white_space (style, HTML_WHITE_SPACE_PRE_LINE);
566 				} else if (!g_ascii_strcasecmp ("inherit", text + 13)) {
567 					style = html_style_set_white_space (style, HTML_WHITE_SPACE_INHERIT);
568 				}
569 				*/
570 			} else if (!g_ascii_strncasecmp ("text-decoration: none", text, 21)) {
571 				style = html_style_unset_decoration (style, ~GTK_HTML_FONT_STYLE_SIZE_MASK);
572 			} else if (!g_ascii_strncasecmp ("display: ", text, 9)) {
573 				gchar *value = text + 9;
574 				if (!g_ascii_strcasecmp ("block", value)) {
575 					style = html_style_set_display (style, DISPLAY_BLOCK);
576 				} else if (!g_ascii_strcasecmp ("inline", value)) {
577 					style = html_style_set_display (style, DISPLAY_INLINE);
578 				} else if (!g_ascii_strcasecmp ("none", value)) {
579 					style = html_style_set_display (style, DISPLAY_NONE);
580 				} else if (!g_ascii_strcasecmp ("inline-table", value)) {
581 					style = html_style_set_display (style, DISPLAY_INLINE_TABLE);
582 				}
583 			} else if (!g_ascii_strncasecmp ("text-align: center", text, 18)) {
584 				style = html_style_add_text_align (style, HTML_HALIGN_CENTER);
585 			} else if (!g_ascii_strncasecmp ("width: ", text, 7)) {
586 				style = html_style_add_width (style, text + 7);
587 			} else if (!g_ascii_strncasecmp ("height: ", text, 8)) {
588 				style = html_style_add_height (style, text + 8);
589 			} else if (!g_ascii_strncasecmp ("clear: ", text, 7)) {
590 				gchar *value = text + 7;
591 
592 				if (!g_ascii_strcasecmp ("left", value)) {
593 					style = html_style_set_clear (style, HTML_CLEAR_LEFT);
594 				} else if (!g_ascii_strcasecmp ("right", value)) {
595 					style = html_style_set_clear (style, HTML_CLEAR_RIGHT);
596 				} else if (!g_ascii_strcasecmp ("both", value)) {
597 					style = html_style_set_clear (style, HTML_CLEAR_ALL);
598 				} else if (!g_ascii_strcasecmp ("inherit", value)) {
599 					style = html_style_set_clear (style, HTML_CLEAR_INHERIT);
600 				} else if (!g_ascii_strcasecmp ("none", value)) {
601 					style = html_style_set_clear (style, HTML_CLEAR_NONE);
602 				}
603 			}
604 		}
605 		g_strfreev (prop);
606 	}
607 	return style;
608 }
609