selector.ml 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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. let is_pseudo_class = function
  7. | Pseudo_class (_, ("link" | "hover" | "visited" | "active"), None) -> true
  8. | _ -> false
  9. (* Specificity (a, b, c, d):
  10. * a = 0 (1 if in style="" definition which is always false in a stylesheet)
  11. * b = number of ID attributes
  12. * c = number of other (pseudo-)attributes
  13. * d = number of (pseudo-)elements
  14. *)
  15. let rec specificity =
  16. let add (a, b, c, d) (e, f, g, h) = (a + e, b + f, c + g, d + h) in
  17. function
  18. | No_element | All_elements ->
  19. (0, 0, 0, 0)
  20. | Element _ ->
  21. (0, 0, 0, 1)
  22. | Id (base, _) ->
  23. add (0, 1, 0, 0) (specificity base)
  24. | Class (base, _) | Attribute (base, _, _) ->
  25. add (0, 0, 1, 0) (specificity base)
  26. | Pseudo_class (base, _, _) as addon when is_pseudo_class addon ->
  27. add (0, 0, 1, 0) (specificity base)
  28. | Pseudo_class (base, _, _) ->
  29. add (0, 0, 0, 1) (specificity base)
  30. (* XXX: Pseudo_element *)
  31. | Combinator (left, _, right) ->
  32. add (specificity left) (specificity right)
  33. let precedes (a, b, c, d) (e, f, g, h) =
  34. let rec loop = function
  35. | [] -> true
  36. | 0 :: tl -> loop tl
  37. | n :: _ when n > 0 -> true
  38. | _ -> false
  39. in
  40. loop [a - e; b - f; c - g; d - h]
  41. let overwrites selector1 selector2 =
  42. precedes (specificity selector1) (specificity selector2)
  43. let can_match_same selector1 selector2 =
  44. let unfold =
  45. let rec loop classes ids pseudos attrs = function
  46. | No_element ->
  47. ("", classes, ids, pseudos, attrs)
  48. | All_elements ->
  49. ("*", classes, ids, pseudos, attrs)
  50. | Element elem ->
  51. (elem, classes, ids, pseudos, attrs)
  52. | Id (base, id) ->
  53. loop classes (id :: ids) pseudos attrs base
  54. | Class (base, cls) ->
  55. loop (cls :: classes) ids pseudos attrs base
  56. | Pseudo (base, f, arg) ->
  57. (* XXX: what about :not(...) ? *)
  58. loop classes ids ((f, arg) :: pseudos) attrs base
  59. | Attribute (base, attr, _) ->
  60. loop classes ids pseudos (attr :: attrs) base
  61. | Combinator (_, _, right) ->
  62. loop classes ids pseudos attrs right
  63. in
  64. loop [] [] [] []
  65. in
  66. let rec intersect l = function
  67. | [] -> false
  68. | hd :: _ when List.mem hd l -> true
  69. | _ :: tl -> intersect l tl
  70. in
  71. let elem1, classes1, ids1, pseudos1, attrs1 = unfold selector1 in
  72. let elem2, classes2, ids2, pseudos2, attrs2 = unfold selector2 in
  73. elem1 = "*" || elem2 = "*" || elem1 = elem2 && elem1 <> "" ||
  74. intersect classes1 classes2 ||
  75. intersect ids1 ids2 ||
  76. intersect pseudos1 pseudos2 ||
  77. intersect attrs1 attrs2