123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- implement Stylesheet;
- include "sys.m";
- sys: Sys;
- include "stylesheet.m";
- include "strmap.m";
- strmap: Strmap;
- Map: import strmap;
- include "cssparser.m";
- Decl: import CSSparser;
- stylemap: ref Map;
- numstyles: int;
- RULEHASH: con 23;
- # specificity:
- # bits 0-26 declaration order
- # bit 27 class count (0 or 1)
- # bit 28 tagname count (0 or 1)
- # bit 28 id count (0 or 1) (inline style only)
- # bit 29-30 origin (0, 1 or 2 - default, reader, author)
- # bit 31 importance
- # order of these as implied by CSS1 §3.2
- TAG,
- CLASS,
- ID: con 1 << (iota + 26);
- ORIGINSHIFT: con 29;
- IMPORTANCE: con 1<<30;
- init(a: array of string)
- {
- sys = load Sys Sys->PATH;
- strmap = load Strmap Strmap->PATH;
- if (strmap == nil) {
- sys->fprint(sys->fildes(2), "stylesheet: cannot load %s: %r\n", Strmap->PATH);
- raise "fail:bad module";
- }
- stylemap = Map.new(a);
- numstyles = len a;
- }
- Sheet.new(): ref Sheet
- {
- return ref Sheet(array[RULEHASH] of list of Rule, 0);
- }
- Sheet.addrules(sheet: self ref Sheet, rules: list of (string, list of Decl), origin: int)
- {
- origin <<= ORIGINSHIFT;
- for (; rules != nil; rules = tl rules) {
- (sel, decls) := hd rules;
- (tag, class) := selector(sel);
- (key, sub) := (tag, "");
- specificity := sheet.ruleid++;
- if (tag != nil)
- specificity |= TAG;
- if (class != nil) {
- specificity |= CLASS;
- (key, sub) = ("." + class, tag);
- }
- specificity |= origin;
- attrs: list of (int, int, string);
- for (; decls != nil; decls = tl decls) {
- d := mkdecl(hd decls, specificity);
- if (d.attrid != -1)
- attrs = d :: attrs;
- }
- n := hashfn(key, RULEHASH);
- sheet.rules[n] = (key, sub, attrs) :: sheet.rules[n];
- }
- }
- # assume selector is well-formed, having been previously parsed.
- selector(s: string): (string, string)
- {
- for (i := 0; i < len s; i++)
- if (s[i] == '.')
- break;
- if (i == len s)
- return (s, nil);
- return (s[0:i], s[i + 1:]);
- }
- Sheet.newstyle(sheet: self ref Sheet): ref Style
- {
- return ref Style(sheet, array[numstyles] of string, array[numstyles] of {* => 0});
- }
- adddecl(style: ref Style, d: Ldecl)
- {
- if (d.specificity > style.spec[d.attrid]) {
- style.attrs[d.attrid] = d.val;
- style.spec[d.attrid] = d.specificity;
- }
- }
- Style.add(style: self ref Style, tag, class: string)
- {
- rules := style.sheet.rules;
- if (class != nil) {
- key := "." + class;
- v := hashfn(key, RULEHASH);
- for (r := rules[v]; r != nil; r = tl r)
- if ((hd r).key == key && ((hd r).sub == nil || (hd r).sub == tag))
- for (decls := (hd r).decls; decls != nil; decls = tl decls)
- adddecl(style, hd decls);
- }
- v := hashfn(tag, RULEHASH);
- for (r := rules[v]; r != nil; r = tl r)
- if ((hd r).key == tag)
- for (decls := (hd r).decls; decls != nil; decls = tl decls)
- adddecl(style, hd decls);
- }
- # add a specific set of attributes to a style;
- # attrs is list of (attrname, important, val).
- Style.adddecls(style: self ref Style, decls: list of Decl)
- {
- specificity := ID | (AUTHOR << ORIGINSHIFT);
- for (; decls != nil; decls = tl decls) {
- d := mkdecl(hd decls, specificity);
- if (d.attrid != -1)
- adddecl(style, d);
- }
- }
- Style.addone(style: self ref Style, attrid: int, origin: int, val: string)
- {
- # XXX specificity is probably wrong here.
- adddecl(style, (attrid, origin << ORIGINSHIFT, val));
- }
- # convert a declaration from extern (attrname, important, val) form
- # to intern (attrid, specificity, val) form.
- # XXX could warn for unknown attribute here...
- mkdecl(d: Decl, specificity: int): Ldecl
- {
- if (d.important)
- specificity |= IMPORTANCE;
- return (stylemap.i(d.name), specificity, d.val);
- }
- hashfn(s: string, n: int): int
- {
- h := 0;
- m := len s;
- for(i:=0; i<m; i++){
- h = 65599*h+s[i];
- }
- return (h & 16r7fffffff) % n;
- }
|