stylesheet.b 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. implement Stylesheet;
  2. include "sys.m";
  3. sys: Sys;
  4. include "stylesheet.m";
  5. include "strmap.m";
  6. strmap: Strmap;
  7. Map: import strmap;
  8. include "cssparser.m";
  9. Decl: import CSSparser;
  10. stylemap: ref Map;
  11. numstyles: int;
  12. RULEHASH: con 23;
  13. # specificity:
  14. # bits 0-26 declaration order
  15. # bit 27 class count (0 or 1)
  16. # bit 28 tagname count (0 or 1)
  17. # bit 28 id count (0 or 1) (inline style only)
  18. # bit 29-30 origin (0, 1 or 2 - default, reader, author)
  19. # bit 31 importance
  20. # order of these as implied by CSS1 §3.2
  21. TAG,
  22. CLASS,
  23. ID: con 1 << (iota + 26);
  24. ORIGINSHIFT: con 29;
  25. IMPORTANCE: con 1<<30;
  26. init(a: array of string)
  27. {
  28. sys = load Sys Sys->PATH;
  29. strmap = load Strmap Strmap->PATH;
  30. if (strmap == nil) {
  31. sys->fprint(sys->fildes(2), "stylesheet: cannot load %s: %r\n", Strmap->PATH);
  32. raise "fail:bad module";
  33. }
  34. stylemap = Map.new(a);
  35. numstyles = len a;
  36. }
  37. Sheet.new(): ref Sheet
  38. {
  39. return ref Sheet(array[RULEHASH] of list of Rule, 0);
  40. }
  41. Sheet.addrules(sheet: self ref Sheet, rules: list of (string, list of Decl), origin: int)
  42. {
  43. origin <<= ORIGINSHIFT;
  44. for (; rules != nil; rules = tl rules) {
  45. (sel, decls) := hd rules;
  46. (tag, class) := selector(sel);
  47. (key, sub) := (tag, "");
  48. specificity := sheet.ruleid++;
  49. if (tag != nil)
  50. specificity |= TAG;
  51. if (class != nil) {
  52. specificity |= CLASS;
  53. (key, sub) = ("." + class, tag);
  54. }
  55. specificity |= origin;
  56. attrs: list of (int, int, string);
  57. for (; decls != nil; decls = tl decls) {
  58. d := mkdecl(hd decls, specificity);
  59. if (d.attrid != -1)
  60. attrs = d :: attrs;
  61. }
  62. n := hashfn(key, RULEHASH);
  63. sheet.rules[n] = (key, sub, attrs) :: sheet.rules[n];
  64. }
  65. }
  66. # assume selector is well-formed, having been previously parsed.
  67. selector(s: string): (string, string)
  68. {
  69. for (i := 0; i < len s; i++)
  70. if (s[i] == '.')
  71. break;
  72. if (i == len s)
  73. return (s, nil);
  74. return (s[0:i], s[i + 1:]);
  75. }
  76. Sheet.newstyle(sheet: self ref Sheet): ref Style
  77. {
  78. return ref Style(sheet, array[numstyles] of string, array[numstyles] of {* => 0});
  79. }
  80. adddecl(style: ref Style, d: Ldecl)
  81. {
  82. if (d.specificity > style.spec[d.attrid]) {
  83. style.attrs[d.attrid] = d.val;
  84. style.spec[d.attrid] = d.specificity;
  85. }
  86. }
  87. Style.add(style: self ref Style, tag, class: string)
  88. {
  89. rules := style.sheet.rules;
  90. if (class != nil) {
  91. key := "." + class;
  92. v := hashfn(key, RULEHASH);
  93. for (r := rules[v]; r != nil; r = tl r)
  94. if ((hd r).key == key && ((hd r).sub == nil || (hd r).sub == tag))
  95. for (decls := (hd r).decls; decls != nil; decls = tl decls)
  96. adddecl(style, hd decls);
  97. }
  98. v := hashfn(tag, RULEHASH);
  99. for (r := rules[v]; r != nil; r = tl r)
  100. if ((hd r).key == tag)
  101. for (decls := (hd r).decls; decls != nil; decls = tl decls)
  102. adddecl(style, hd decls);
  103. }
  104. # add a specific set of attributes to a style;
  105. # attrs is list of (attrname, important, val).
  106. Style.adddecls(style: self ref Style, decls: list of Decl)
  107. {
  108. specificity := ID | (AUTHOR << ORIGINSHIFT);
  109. for (; decls != nil; decls = tl decls) {
  110. d := mkdecl(hd decls, specificity);
  111. if (d.attrid != -1)
  112. adddecl(style, d);
  113. }
  114. }
  115. Style.addone(style: self ref Style, attrid: int, origin: int, val: string)
  116. {
  117. # XXX specificity is probably wrong here.
  118. adddecl(style, (attrid, origin << ORIGINSHIFT, val));
  119. }
  120. # convert a declaration from extern (attrname, important, val) form
  121. # to intern (attrid, specificity, val) form.
  122. # XXX could warn for unknown attribute here...
  123. mkdecl(d: Decl, specificity: int): Ldecl
  124. {
  125. if (d.important)
  126. specificity |= IMPORTANCE;
  127. return (stylemap.i(d.name), specificity, d.val);
  128. }
  129. hashfn(s: string, n: int): int
  130. {
  131. h := 0;
  132. m := len s;
  133. for(i:=0; i<m; i++){
  134. h = 65599*h+s[i];
  135. }
  136. return (h & 16r7fffffff) % n;
  137. }