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