1 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
3 #line 1 "term-styled-ostream.oo.c"
4 /* Output stream for CSS styled text, producing ANSI escape sequences.
5 Copyright (C) 2006-2007, 2015 Free Software Foundation, Inc.
6 Written by Bruno Haible <bruno@clisp.org>, 2006.
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 #include "term-styled-ostream.h"
28 #include <cr-om-parser.h>
29 #include <cr-sel-eng.h>
32 /* <cr-fonts.h> has a broken double-inclusion guard in libcroco-0.6.1. */
33 #ifndef __CR_FONTS_H__
34 # include <cr-fonts.h>
36 #include <cr-string.h>
38 #include "term-ostream.h"
43 /* CSS matching works as follows:
44 Suppose we have an element inside class "header" inside class "table".
45 We pretend to have an XML tree that looks like this:
51 For each of these XML nodes, the CSS matching engine can report the
52 matching CSS declarations. We extract the CSS property values that
53 matter for terminal styling and cache them. */
55 /* Attributes that can be set on a character. */
61 term_posture_t posture;
62 term_underline_t underline;
65 #line 66 "term-styled-ostream.c"
67 #define term_styled_ostream_representation any_ostream_representation
69 #include "term_styled_ostream.priv.h"
71 const typeinfo_t term_styled_ostream_typeinfo = { "term_styled_ostream" };
73 static const typeinfo_t * const term_styled_ostream_superclasses[] =
74 { term_styled_ostream_SUPERCLASSES };
76 #define super styled_ostream_vtable
78 #line 82 "term-styled-ostream.oo.c"
80 /* Implementation of ostream_t methods. */
83 term_styled_ostream__write_mem (term_styled_ostream_t stream,
84 const void *data, size_t len)
86 term_ostream_set_color (stream->destination, stream->curr_attr->color);
87 term_ostream_set_bgcolor (stream->destination, stream->curr_attr->bgcolor);
88 term_ostream_set_weight (stream->destination, stream->curr_attr->weight);
89 term_ostream_set_posture (stream->destination, stream->curr_attr->posture);
90 term_ostream_set_underline (stream->destination, stream->curr_attr->underline);
92 term_ostream_write_mem (stream->destination, data, len);
96 term_styled_ostream__flush (term_styled_ostream_t stream)
98 term_ostream_flush (stream->destination);
102 term_styled_ostream__free (term_styled_ostream_t stream)
104 term_ostream_free (stream->destination);
105 cr_cascade_destroy (stream->css_document);
106 cr_sel_eng_destroy (stream->css_engine);
107 free (stream->curr_classes);
114 while (hash_iterate (&stream->cache, &ptr, &key, &keylen, &data) == 0)
119 hash_destroy (&stream->cache);
123 /* Implementation of styled_ostream_t methods. */
125 /* CRStyle doesn't contain a value for the 'text-decoration' property.
126 So we have to extend it. */
128 enum CRXTextDecorationType
130 TEXT_DECORATION_NONE,
131 TEXT_DECORATION_UNDERLINE,
132 TEXT_DECORATION_OVERLINE,
133 TEXT_DECORATION_LINE_THROUGH,
134 TEXT_DECORATION_BLINK,
135 TEXT_DECORATION_INHERIT
138 typedef struct _CRXStyle
140 struct _CRXStyle *parent_style;
142 enum CRXTextDecorationType text_decoration;
145 /* An extended version of cr_style_new. */
147 crx_style_new (gboolean a_set_props_to_initial_values)
152 base = cr_style_new (a_set_props_to_initial_values);
156 result = XMALLOC (CRXStyle);
158 if (a_set_props_to_initial_values)
159 result->text_decoration = TEXT_DECORATION_NONE;
161 result->text_decoration = TEXT_DECORATION_INHERIT;
166 /* An extended version of cr_style_destroy. */
168 crx_style_destroy (CRXStyle *a_style)
170 cr_style_destroy (a_style->base);
174 /* An extended version of cr_sel_eng_get_matched_style. */
176 crx_sel_eng_get_matched_style (CRSelEng * a_this, CRCascade * a_cascade,
178 CRXStyle * a_parent_style, CRXStyle ** a_style,
179 gboolean a_set_props_to_initial_values)
181 enum CRStatus status;
182 CRPropList *props = NULL;
184 if (!(a_this && a_cascade && a_node && a_style))
185 return CR_BAD_PARAM_ERROR;
187 status = cr_sel_eng_get_matched_properties_from_cascade (a_this, a_cascade,
189 if (!(status == CR_OK))
198 *a_style = crx_style_new (a_set_props_to_initial_values);
204 if (a_set_props_to_initial_values)
206 cr_style_set_props_to_initial_values ((*a_style)->base);
207 (*a_style)->text_decoration = TEXT_DECORATION_NONE;
211 cr_style_set_props_to_default_values ((*a_style)->base);
212 (*a_style)->text_decoration = TEXT_DECORATION_INHERIT;
216 style->parent_style = a_parent_style;
217 style->base->parent_style =
218 (a_parent_style != NULL ? a_parent_style->base : NULL);
223 for (cur = props; cur != NULL; cur = cr_prop_list_get_next (cur))
225 CRDeclaration *decl = NULL;
227 cr_prop_list_get_decl (cur, &decl);
228 cr_style_set_style_from_decl (style->base, decl);
230 && decl->property != NULL
231 && decl->property->stryng != NULL
232 && decl->property->stryng->str != NULL)
234 if (strcmp (decl->property->stryng->str, "text-decoration") == 0
235 && decl->value != NULL
236 && decl->value->type == TERM_IDENT
237 && decl->value->content.str != NULL)
240 cr_string_peek_raw_str (decl->value->content.str);
244 if (strcmp (value, "none") == 0)
245 style->text_decoration = TEXT_DECORATION_NONE;
246 else if (strcmp (value, "underline") == 0)
247 style->text_decoration = TEXT_DECORATION_UNDERLINE;
248 else if (strcmp (value, "overline") == 0)
249 style->text_decoration = TEXT_DECORATION_OVERLINE;
250 else if (strcmp (value, "line-through") == 0)
251 style->text_decoration = TEXT_DECORATION_LINE_THROUGH;
252 else if (strcmp (value, "blink") == 0)
253 style->text_decoration = TEXT_DECORATION_BLINK;
254 else if (strcmp (value, "inherit") == 0)
255 style->text_decoration = TEXT_DECORATION_INHERIT;
262 cr_prop_list_destroy (props);
268 /* According to the CSS2 spec, sections 6.1 and 6.2, we need to do a
269 propagation: specified values -> computed values -> actual values.
270 The computed values are necessary. libcroco does not compute them for us.
271 The function cr_style_resolve_inherited_properties is also not sufficient:
272 it handles only the case of inheritance, not the case of non-inheritance.
273 So we write style accessors that fetch the computed value, doing the
274 inheritance on the fly.
275 We then compute the actual values from the computed values; for colors,
276 this is done through the rgb_to_color method. */
279 style_compute_color_value (CRStyle *style, enum CRRgbProp which,
280 term_ostream_t stream)
285 return COLOR_DEFAULT;
286 if (cr_rgb_is_set_to_inherit (&style->rgb_props[which].sv))
287 style = style->parent_style;
288 else if (cr_rgb_is_set_to_transparent (&style->rgb_props[which].sv))
289 /* A transparent color occurs as default background color, set by
290 cr_style_set_props_to_default_values. */
291 return COLOR_DEFAULT;
299 cr_rgb_copy (&rgb, &style->rgb_props[which].sv);
300 if (cr_rgb_compute_from_percentage (&rgb) != CR_OK)
303 g = rgb.green & 0xff;
305 return term_ostream_rgb_to_color (stream, r, g, b);
311 style_compute_font_weight_value (const CRStyle *style)
319 switch (style->font_weight)
321 case FONT_WEIGHT_INHERIT:
322 style = style->parent_style;
324 case FONT_WEIGHT_BOLDER:
326 style = style->parent_style;
328 case FONT_WEIGHT_LIGHTER:
330 style = style->parent_style;
332 case FONT_WEIGHT_100:
335 case FONT_WEIGHT_200:
338 case FONT_WEIGHT_300:
341 case FONT_WEIGHT_400: case FONT_WEIGHT_NORMAL:
344 case FONT_WEIGHT_500:
347 case FONT_WEIGHT_600:
350 case FONT_WEIGHT_700: case FONT_WEIGHT_BOLD:
353 case FONT_WEIGHT_800:
356 case FONT_WEIGHT_900:
362 /* Value >= 600 -> WEIGHT_BOLD. Value <= 500 -> WEIGHT_NORMAL. */
363 return (value >= 6 ? WEIGHT_BOLD : WEIGHT_NORMAL);
367 static term_posture_t
368 style_compute_font_posture_value (const CRStyle *style)
373 return POSTURE_DEFAULT;
374 switch (style->font_style)
376 case FONT_STYLE_INHERIT:
377 style = style->parent_style;
379 case FONT_STYLE_NORMAL:
380 return POSTURE_NORMAL;
381 case FONT_STYLE_ITALIC:
382 case FONT_STYLE_OBLIQUE:
383 return POSTURE_ITALIC;
390 static term_underline_t
391 style_compute_text_underline_value (const CRXStyle *style)
396 return UNDERLINE_DEFAULT;
397 switch (style->text_decoration)
399 case TEXT_DECORATION_INHERIT:
400 style = style->parent_style;
402 case TEXT_DECORATION_NONE:
403 case TEXT_DECORATION_OVERLINE:
404 case TEXT_DECORATION_LINE_THROUGH:
405 case TEXT_DECORATION_BLINK:
406 return UNDERLINE_OFF;
407 case TEXT_DECORATION_UNDERLINE:
415 /* Match the current list of CSS classes to the CSS and return the result. */
416 static attributes_t *
417 match (term_styled_ostream_t stream)
423 CRXStyle *curr_style;
424 CRStyle *curr_style_base;
427 /* Create a hierarchy of XML nodes. */
428 root = xmlNewNode (NULL, (const xmlChar *) "__root__");
429 root->type = XML_ELEMENT_NODE;
431 p_end = &stream->curr_classes[stream->curr_classes_length];
432 p_start = stream->curr_classes;
433 while (p_start < p_end)
438 if (!(*p_start == ' '))
441 for (p = p_start; p < p_end && *p != ' '; p++)
444 /* Temporarily replace the ' ' by '\0'. */
446 child = xmlNewNode (NULL, (const xmlChar *) p_start);
447 child->type = XML_ELEMENT_NODE;
448 xmlSetProp (child, (const xmlChar *) "class", (const xmlChar *) p_start);
451 if (xmlAddChild (curr, child) == NULL)
452 /* Error! Shouldn't happen. */
459 /* Retrieve the matching CSS declarations. */
460 /* Not curr_style = crx_style_new (TRUE); because that assumes that the
461 default foreground color is black and that the default background color
462 is white, which is not necessarily true in a terminal context. */
464 for (curr = root; curr != NULL; curr = curr->children)
466 CRXStyle *parent_style = curr_style;
469 if (crx_sel_eng_get_matched_style (stream->css_engine,
470 stream->css_document,
472 parent_style, &curr_style,
475 if (curr_style == NULL)
476 /* No declarations matched this node. Inherit all values. */
477 curr_style = parent_style;
479 /* curr_style is a new style, inheriting from parent_style. */
482 curr_style_base = (curr_style != NULL ? curr_style->base : NULL);
484 /* Extract the CSS declarations that we can use. */
485 attr = XMALLOC (attributes_t);
487 style_compute_color_value (curr_style_base, RGB_PROP_COLOR,
488 stream->destination);
490 style_compute_color_value (curr_style_base, RGB_PROP_BACKGROUND_COLOR,
491 stream->destination);
492 attr->weight = style_compute_font_weight_value (curr_style_base);
493 attr->posture = style_compute_font_posture_value (curr_style_base);
494 attr->underline = style_compute_text_underline_value (curr_style);
496 /* Free the style chain. */
497 while (curr_style != NULL)
499 CRXStyle *parent_style = curr_style->parent_style;
501 crx_style_destroy (curr_style);
502 curr_style = parent_style;
505 /* Free the XML nodes. */
506 xmlFreeNodeList (root);
511 /* Match the current list of CSS classes to the CSS and store the result in
512 stream->curr_attr and in the cache. */
514 match_and_cache (term_styled_ostream_t stream)
516 attributes_t *attr = match (stream);
517 if (hash_insert_entry (&stream->cache,
518 stream->curr_classes, stream->curr_classes_length,
521 stream->curr_attr = attr;
525 term_styled_ostream__begin_use_class (term_styled_ostream_t stream,
526 const char *classname)
528 size_t classname_len;
532 if (classname[0] == '\0' || strchr (classname, ' ') != NULL)
533 /* Invalid classname argument. */
536 /* Push the classname onto the classname list. */
537 classname_len = strlen (classname);
538 if (stream->curr_classes_length + 1 + classname_len + 1
539 > stream->curr_classes_allocated)
541 size_t new_allocated = stream->curr_classes_length + 1 + classname_len + 1;
542 if (new_allocated < 2 * stream->curr_classes_allocated)
543 new_allocated = 2 * stream->curr_classes_allocated;
545 stream->curr_classes = xrealloc (stream->curr_classes, new_allocated);
546 stream->curr_classes_allocated = new_allocated;
548 p = &stream->curr_classes[stream->curr_classes_length];
550 memcpy (p, classname, classname_len);
551 stream->curr_classes_length += 1 + classname_len;
553 /* Uodate stream->curr_attr. */
554 if (hash_find_entry (&stream->cache,
555 stream->curr_classes, stream->curr_classes_length,
557 match_and_cache (stream);
559 stream->curr_attr = (attributes_t *) found;
563 term_styled_ostream__end_use_class (term_styled_ostream_t stream,
564 const char *classname)
571 if (stream->curr_classes_length == 0)
572 /* No matching call to begin_use_class. */
575 /* Remove the trailing classname. */
576 p_end = &stream->curr_classes[stream->curr_classes_length];
581 if (!(p_end - p_start == strlen (classname)
582 && memcmp (p_start, classname, p_end - p_start) == 0))
583 /* The match ing call to begin_use_class used a different classname. */
585 stream->curr_classes_length = p - stream->curr_classes;
587 /* Update stream->curr_attr. */
588 if (hash_find_entry (&stream->cache,
589 stream->curr_classes, stream->curr_classes_length,
592 stream->curr_attr = (attributes_t *) found;
597 term_styled_ostream_t
598 term_styled_ostream_create (int fd, const char *filename,
599 const char *css_filename)
601 term_styled_ostream_t stream =
602 XMALLOC (struct term_styled_ostream_representation);
603 CRStyleSheet *css_file_contents;
605 stream->base.base.vtable = &term_styled_ostream_vtable;
606 stream->destination = term_ostream_create (fd, filename);
608 if (cr_om_parser_simply_parse_file ((const guchar *) css_filename,
609 CR_UTF_8, /* CR_AUTO is not supported */
610 &css_file_contents) != CR_OK)
612 term_ostream_free (stream->destination);
616 stream->css_document = cr_cascade_new (NULL, css_file_contents, NULL);
617 stream->css_engine = cr_sel_eng_new ();
619 stream->curr_classes_allocated = 60;
620 stream->curr_classes = XNMALLOC (stream->curr_classes_allocated, char);
621 stream->curr_classes_length = 0;
623 hash_init (&stream->cache, 10);
625 match_and_cache (stream);
630 #line 631 "term-styled-ostream.c"
632 const struct term_styled_ostream_implementation term_styled_ostream_vtable =
634 term_styled_ostream_superclasses,
635 sizeof (term_styled_ostream_superclasses) / sizeof (term_styled_ostream_superclasses[0]),
636 sizeof (struct term_styled_ostream_representation),
637 term_styled_ostream__write_mem,
638 term_styled_ostream__flush,
639 term_styled_ostream__free,
640 term_styled_ostream__begin_use_class,
641 term_styled_ostream__end_use_class,
646 /* Define the functions that invoke the methods. */
649 term_styled_ostream_write_mem (term_styled_ostream_t first_arg, const void *data, size_t len)
651 const struct term_styled_ostream_implementation *vtable =
652 ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
653 vtable->write_mem (first_arg,data,len);
657 term_styled_ostream_flush (term_styled_ostream_t first_arg)
659 const struct term_styled_ostream_implementation *vtable =
660 ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
661 vtable->flush (first_arg);
665 term_styled_ostream_free (term_styled_ostream_t first_arg)
667 const struct term_styled_ostream_implementation *vtable =
668 ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
669 vtable->free (first_arg);
673 term_styled_ostream_begin_use_class (term_styled_ostream_t first_arg, const char *classname)
675 const struct term_styled_ostream_implementation *vtable =
676 ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
677 vtable->begin_use_class (first_arg,classname);
681 term_styled_ostream_end_use_class (term_styled_ostream_t first_arg, const char *classname)
683 const struct term_styled_ostream_implementation *vtable =
684 ((struct term_styled_ostream_representation_header *) (struct term_styled_ostream_representation *) first_arg)->vtable;
685 vtable->end_use_class (first_arg,classname);