📄 apply.c
字号:
/* CSS style applier *//* $Id: apply.c,v 1.90.4.2 2005/01/29 01:01:21 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#include <string.h>#include "elinks.h"#include "document/css/apply.h"#include "document/css/css.h"#include "document/css/parser.h"#include "document/css/property.h"#include "document/css/scanner.h"#include "document/css/stylesheet.h"#include "document/html/parser/parse.h"#include "document/options.h"#include "util/align.h"#include "util/color.h"#include "util/lists.h"#include "util/error.h"#include "util/memory.h"#include "util/string.h"/* #define DEBUG_CSS *//* TODO: A way to disable CSS completely, PLUS a way to stop various property * groups from taking effect. (Ie. way to turn out effect of 'display: none' * or aligning or colors but keeping all the others.) --pasky */typedef void (*css_applier_t)(struct html_element *element, struct css_property *prop);static voidcss_apply_color(struct html_element *element, struct css_property *prop){ assert(prop->value_type == CSS_VT_COLOR); if (use_document_fg_colors(global_doc_opts)) element->attr.style.fg = prop->value.color;}static voidcss_apply_background_color(struct html_element *element, struct css_property *prop){ assert(prop->value_type == CSS_VT_COLOR); if (use_document_bg_colors(global_doc_opts)) element->attr.style.bg = prop->value.color;}static voidcss_apply_font_attribute(struct html_element *element, struct css_property *prop){ assert(prop->value_type == CSS_VT_FONT_ATTRIBUTE); element->attr.style.attr |= prop->value.font_attribute.add; element->attr.style.attr &= ~prop->value.font_attribute.rem;}/* FIXME: Because the current CSS doesn't provide reasonable defaults for each * HTML element this applier will cause bad rendering of <pre> tags. */static voidcss_apply_text_align(struct html_element *element, struct css_property *prop){ assert(prop->value_type == CSS_VT_TEXT_ALIGN); element->parattr.align = prop->value.text_align;}/* XXX: Sort like the css_property_type */static css_applier_t css_appliers[CSS_PT_LAST] = { /* CSS_PT_NONE */ NULL, /* CSS_PT_BACKGROUND */ css_apply_background_color, /* CSS_PT_BACKGROUND_COLOR */ css_apply_background_color, /* CSS_PT_COLOR */ css_apply_color, /* CSS_PT_FONT_STYLE */ css_apply_font_attribute, /* CSS_PT_FONT_WEIGHT */ css_apply_font_attribute, /* CSS_PT_TEXT_ALIGN */ css_apply_text_align, /* CSS_PT_TEXT_DECORATION */ css_apply_font_attribute, /* CSS_PT_WHITE_SPACE */ css_apply_font_attribute,};/* This looks for a match in list of selectors. */static voidexamine_element(struct css_selector *base, enum css_selector_type seltype, enum css_selector_relation rel, struct list_head *selectors, struct html_element *element, struct list_head *html_stack){ struct css_selector *selector; unsigned char *code;#ifdef DEBUG_CSS DBG("examine_element(%s, %d, %d, %p, %.*s);", base->name, seltype, rel, selectors, element->namelen, element->name);#define dbginfo(sel, type_, base) \ DBG("Matched selector %s (rel %d type %d [m%d])! Children %p !!%d, props !!%d", sel->name, sel->relation, sel->type, sel->type == type_, &sel->leaves, !list_empty(sel->leaves), !list_empty(sel->properties))#else#define dbginfo(sel, type, base)#endif#define process_found_selector(sel, type, base) \ if (selector) { \ dbginfo(sel, type, base); \ merge_css_selectors(base, sel); \ /* Ancestor matches? */ \ if ((struct list_head *) element->next != html_stack) { \ struct html_element *ancestor; \ /* This is less effective than doing reverse iterations, * first over sel->leaves and then over the HTML stack, * which shines in the most common case where there are * no CSR_ANCESTOR selector leaves. However we would * have to duplicate the whole examine_element(), so if * profiles won't show it really costs... */ \ for (ancestor = element->next; \ (struct list_head *) ancestor != html_stack;\ ancestor = ancestor->next) \ examine_element(base,CST_ELEMENT,CSR_ANCESTOR, \ &sel->leaves, ancestor, \ html_stack); \ examine_element(base, CST_ELEMENT, CSR_PARENT, \ &sel->leaves, element->next, \ html_stack); \ } \ /* More specific matches? */ \ examine_element(base, type + 1, CSR_SPECIFITY, \ &sel->leaves, element, html_stack); \ } if (seltype <= CST_ELEMENT && element->namelen) { selector = find_css_selector(selectors, CST_ELEMENT, rel, "*", 1); process_found_selector(selector, CST_ELEMENT, base); selector = find_css_selector(selectors, CST_ELEMENT, rel, element->name, element->namelen); process_found_selector(selector, CST_ELEMENT, base); } if (!element->options) return; /* TODO: More pseudo-classess. --pasky */ if (element->pseudo_class & ELEMENT_LINK) { selector = find_css_selector(selectors, CST_PSEUDO, rel, "link", -1); process_found_selector(selector, CST_PSEUDO, base); } if (element->pseudo_class & ELEMENT_VISITED) { selector = find_css_selector(selectors, CST_PSEUDO, rel, "visited", -1); process_found_selector(selector, CST_PSEUDO, base); } code = get_attr_val(element->options, "class"); if (code && seltype <= CST_CLASS) { selector = find_css_selector(selectors, CST_CLASS, rel, code, -1); process_found_selector(selector, CST_CLASS, base); } if (code) mem_free(code); code = get_attr_val(element->options, "id"); if (code && seltype <= CST_ID) { selector = find_css_selector(selectors, CST_ID, rel, code, -1); process_found_selector(selector, CST_ID, base); } if (code) mem_free(code);#undef process_found_selector#undef dbginfo}struct css_selector *get_css_selector_for_element(struct html_element *element, struct css_stylesheet *css, struct list_head *html_stack){ unsigned char *code; struct css_selector *selector; assert(element && element->options && css); selector = init_css_selector(NULL, CST_ELEMENT, NULL, 0); if (!selector) return NULL;#ifdef DEBUG_CSS DBG("Applying to element %.*s...", element->namelen, element->name);#endif examine_element(selector, CST_ELEMENT, CSR_ROOT, &css->selectors, element, html_stack);#ifdef DEBUG_CSS DBG("Element %.*s applied.", element->namelen, element->name);#endif code = get_attr_val(element->options, "style"); if (code) { struct css_selector *stylesel; struct scanner scanner; stylesel = init_css_selector(NULL, CST_ELEMENT, NULL, 0); if (stylesel) { init_scanner(&scanner, &css_scanner_info, code, NULL); css_parse_properties(&stylesel->properties, &scanner); merge_css_selectors(selector, stylesel); done_css_selector(stylesel); } mem_free(code); } return selector;}voidapply_css_selector_style(struct html_element *element, struct css_selector *selector){ struct css_property *property; foreach (property, selector->properties) { assert(property->type < CSS_PT_LAST); /* We don't assert general prop->value_type here because I * don't want hinder properties' ability to potentially make * use of multiple value types. */ assert(css_appliers[property->type]); css_appliers[property->type](element, property); }}voidcss_apply(struct html_element *element, struct css_stylesheet *css, struct list_head *html_stack){ struct css_selector *selector; selector = get_css_selector_for_element(element, css, html_stack); if (!selector) return; apply_css_selector_style(element, selector); done_css_selector(selector);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -