selector.ml 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. open Types
  2. (* This file defines functions that construct an element tree with applied
  3. * stylesheet based on:
  4. * - http://www.w3.org/TR/CSS2/cascade.html#specificity
  5. *)
  6. (* Specificity (a, b, c, d):
  7. * a = 0 (1 if in style="" definition which is always false in a stylesheet)
  8. * b = number of ID attributes
  9. * c = number of other (pseudo-)attributes
  10. * d = number of (pseudo-)elements
  11. *)
  12. let rec specificity =
  13. let add (a, b, c, d) (e, f, g, h) = (a + e, b + f, c + g, d + h) in
  14. function
  15. | No_element | All_elements ->
  16. (0, 0, 0, 0)
  17. | Element _ ->
  18. (0, 0, 0, 1)
  19. | Id (base, _) ->
  20. add (0, 1, 0, 0) (specificity base)
  21. | Class (base, _) | Attribute (base, _, _) | Pseudo_class (base, _, _) ->
  22. add (0, 0, 1, 0) (specificity base)
  23. | Pseudo_element (base, _) ->
  24. add (0, 0, 0, 1) (specificity base)
  25. | Combinator (left, _, right) ->
  26. add (specificity left) (specificity right)
  27. let precedes (a, b, c, d) (e, f, g, h) =
  28. let rec loop = function
  29. | [] -> true
  30. | 0 :: tl -> loop tl
  31. | n :: _ when n > 0 -> true
  32. | _ -> false
  33. in
  34. loop [a - e; b - f; c - g; d - h]
  35. let overwrites selector1 selector2 =
  36. precedes (specificity selector1) (specificity selector2)
  37. let can_match_same selector1 selector2 =
  38. let unfold =
  39. let rec loop classes ids pseudos attrs = function
  40. | No_element ->
  41. ("", classes, ids, pseudos, attrs)
  42. | All_elements ->
  43. ("*", classes, ids, pseudos, attrs)
  44. | Element elem ->
  45. (elem, classes, ids, pseudos, attrs)
  46. | Id (base, id) ->
  47. loop classes (id :: ids) pseudos attrs base
  48. | Class (base, cls) ->
  49. loop (cls :: classes) ids pseudos attrs base
  50. | Pseudo (base, f, arg) ->
  51. (* XXX: what about :not(...) ? *)
  52. loop classes ids ((f, arg) :: pseudos) attrs base
  53. | Attribute (base, attr, _) ->
  54. loop classes ids pseudos (attr :: attrs) base
  55. | Combinator (_, _, right) ->
  56. loop classes ids pseudos attrs right
  57. in
  58. loop [] [] [] []
  59. in
  60. let rec intersect l = function
  61. | [] -> false
  62. | hd :: _ when List.mem hd l -> true
  63. | _ :: tl -> intersect l tl
  64. in
  65. let elem1, classes1, ids1, pseudos1, attrs1 = unfold selector1 in
  66. let elem2, classes2, ids2, pseudos2, attrs2 = unfold selector2 in
  67. elem1 = "*" || elem2 = "*" || elem1 = elem2 && elem1 <> "" ||
  68. intersect classes1 classes2 ||
  69. intersect ids1 ids2 ||
  70. intersect pseudos1 pseudos2 ||
  71. intersect attrs1 attrs2