示例#1
0
static fz_css_selector *parse_adjacent_selector(struct lexbuf *buf)
{
	fz_css_selector *s, *a, *b;

	a = parse_simple_selector(buf);
	if (accept(buf, '+'))
	{
		b = parse_adjacent_selector(buf);
		s = fz_new_css_selector(buf->ctx, NULL);
		s->combine = '+';
		s->left = a;
		s->right = b;
		return s;
	}
	return a;
}
示例#2
0
/* flags: only XML_IGNORE_CASE is handled */
void css_parse_style_sheet(CSSStyleSheet *s, CSSParseState *b)
{
    char value[1024];
    char tag[64];
    char tag_id[64];
    char *q;
    int ch, media, val, last_tree_op, i;
    CSSStyleSheetEntry *e, **first_eprops;
    CSSSimpleSelector ss2, *ss = &ss2, *last_ss, *ss1;
    CSSProperty *props;

    ch = bgetc(b);
    media = CSS_MEDIA_ALL;
    for (;;) {
redo:
        first_eprops = s->plast_entry;
        bskip_spaces(b, &ch);
        if (ch == EOF)
            break;
        /* eat inserted HTML comments for compatible STYLE tag parsing */
        if (ch == '<') {
            beat(b, &ch, "<!--");
            goto redo;
        } else if (ch == '-') {
            beat(b, &ch, "-->");
            goto redo;
        }

        /* handle '@media { ... }' */
        if (ch == '@') {
            ch = bgetc(b);
            read_ident(b, &ch, tag, sizeof(tag));
            switch (css_get_enum(tag, "media,page")) {
            case 0:
                /* @media */
                media = 0;
                for (;;) {
                    bskip_spaces(b, &ch);
                    read_ident(b, &ch, tag, sizeof(tag));
                    val = css_get_enum(tag, "tty,screen,print,tv,speech,all");
                    if (val < 0 || val == 5)
                        media = CSS_MEDIA_ALL;
                    else
                        media |= (1 << val);
                    bskip_spaces(b, &ch);
                    if (ch == ',') {
                        ch = bgetc(b);
                    } else if (ch == '{' || ch == EOF) {
                        ch = bgetc(b);
                        break;
                    }
                }
                goto redo;
            case 1:
                /* @page */
                bskip_spaces(b, &ch);
                if (ch != '{') {
                    read_ident(b, &ch, tag_id, sizeof(tag_id));
                    bskip_spaces(b, &ch);
                }
                memset(ss, 0, sizeof(CSSSimpleSelector));
                ss->tag = css_new_ident("@page");
                if (tag_id[0] != '\0')
                    ss->tag_id = css_new_ident(tag_id);
                add_style_entry(s, ss, media);
                goto parse_props;
            default:
                css_error1(b, "unrecognized css directive '@%s'", tag);
                break;
            }
        } else if (ch == '}') {
            /* XXX: end of media, should unstack */
            ch = bgetc(b);
            goto redo;
        }

        /* parse a selector list */
        for (;;) {
            /* parse simple selectors with operations */
            last_ss = NULL;
            last_tree_op = CSS_TREE_OP_NONE;
            for (;;) {
                int tree_op;
                bskip_spaces(b, &ch);
                parse_simple_selector(ss, b, &ch);
                bskip_spaces(b, &ch);
                ss->tree_op = last_tree_op;
                ss->next = last_ss;
                if (ch == '+') {
                    tree_op = CSS_TREE_OP_PRECEEDED;
                    ch = bgetc(b);
                    goto add_tree;
                } else if (ch == '>') {
                    tree_op = CSS_TREE_OP_CHILD;
                    ch = bgetc(b);
                    goto add_tree;
                } else if (isalpha(ch)) {
                    tree_op = CSS_TREE_OP_DESCENDANT;
add_tree:
                    ss1 = malloc(sizeof(CSSSimpleSelector));
                    if (ss1) {
                        memcpy(ss1, ss, sizeof(CSSSimpleSelector));
                        last_ss = ss1;
                    }
                    last_tree_op = tree_op;
                } else {
                    /* other char: exit */
                    break;
                }
            }
            add_style_entry(s, ss, media);

            /* get next selector, if present */
            if (ch != ',')
                break;
            ch = bgetc(b);
        }
parse_props:
        /* expect start of properties */
        if (ch != '{')
            break;
        ch = bgetc(b);

        q = value;
        while (ch != '}' && ch != EOF) {
            if ((q - value) < (int)sizeof(value) - 1)
                *q++ = ch;
            ch = bgetc(b);
        }
        *q = '\0';

        if (ch == '}')
            ch = bgetc(b);

        /* the properties are extracted, now add them to each tag */
        /* XXX: should locate entries first, then add, to avoid adding
           duplicate entries */
        /* XXX: should put font properties first to avoid em/ex units
           problems, but it would still not be sufficient. */
        props = css_parse_properties(b, value);
        i = 0;
        for (e = *first_eprops; e != NULL; e = e->next) {
            if (i == 0)
                e->props = props;
            else
                e->props = dup_properties(props);
            i++;
        }
    }
#ifdef DEBUG
    css_dump_style_sheet(s);
#endif
}