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.2TAG,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;}
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;
}