Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
// $Header: /cvsroot/html2ps/css.selectors.inc.php,v 1.12 2006/01/07 19:38:06 Konstantin Exp $
3
 
4
define('SELECTOR_ID'   ,1);
5
define('SELECTOR_CLASS',2);
6
define('SELECTOR_TAG'  ,3);
7
define('SELECTOR_TAG_CLASS',4);
8
define('SELECTOR_SEQUENCE', 5);
9
define('SELECTOR_PARENT', 6);         // TAG1 TAG2
10
define('SELECTOR_ATTR_VALUE', 7);
11
define('SELECTOR_PSEUDOCLASS_LINK', 8);
12
define('SELECTOR_ATTR', 9);
13
define('SELECTOR_DIRECT_PARENT', 10); // TAG1 > TAG2
14
define('SELECTOR_LANGUAGE', 11);      // SELECTOR:lang(..)
15
 
16
// Used for handling the body 'link' atttribute; this selector have no specificity at all
17
// we need to introduce this selector type as some ill-brained designers use constructs like:
18
//
19
// <html>
20
// <head><style type="text/css">a { color: red; }</style></head>
21
// <body link="#000000"><a href="test">test</a>
22
//
23
// in this case the CSS rule should have the higher priority; nevertheless, using the default selector rules
24
// we'd get find that 'link'-generated CSS rule is more important
25
//
26
define('SELECTOR_PSEUDOCLASS_LINK_LOW_PRIORITY', 12);
27
 
28
// Used for hanling the following case:
29
//
30
// <head>
31
// <style>img { border: 0; }</style>
32
// </head>
33
// <body><a href=""><img height="10" width="10" src=""></a>
34
//
35
define('SELECTOR_PARENT_LOW_PRIORITY', 13);
36
 
37
define('SELECTOR_PSEUDOELEMENT_BEFORE', 14);
38
define('SELECTOR_PSEUDOELEMENT_AFTER', 15);
39
 
40
// Note on SELECTOR_ANY:
41
// normally we should not process rules like
42
// * html <some other selector> as they're IE specific and (according to CSS standard)
43
// should be never matched
44
define('SELECTOR_ANY', 16);
45
 
46
define('SELECTOR_ATTR_VALUE_WORD',17);
47
 
48
// CSS 2.1:
49
// In CSS2, identifiers  (including element names, classes, and IDs in selectors) can contain only the characters [A-Za-z0-9] and
50
// ISO 10646 characters 161 and higher, plus the hyphen (-); they cannot start with a hyphen or a digit.
51
// They can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). For instance,
52
// the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F".
53
//
54
// Any node can be marked by several space separated class names
55
//
56
function node_have_class($root, $target_class) {
57
  if (!$root->has_attribute('class')) { return false; };
58
 
59
  $classes = preg_split("/\s+/", strtolower($root->get_attribute('class')));
60
 
61
  foreach ($classes as $class) {
62
    if ($class == $target_class) {
63
      return true;
64
    };
65
  };
66
 
67
  return false;
68
};
69
 
70
function match_selector($selector, $root) {
71
  switch ($selector[0]) {
72
  case SELECTOR_TAG:
73
    if ($selector[1] == strtolower($root->tagname())) { return true; };
74
    break;
75
  case SELECTOR_ID:
76
    if ($selector[1] == strtolower($root->get_attribute('id'))) { return true; };
77
    break;
78
  case SELECTOR_CLASS:
79
    if (node_have_class($root, $selector[1])) { return true; }
80
    if ($selector[1] == strtolower($root->get_attribute('class'))) { return true; };
81
    break;
82
  case SELECTOR_TAG_CLASS:
83
    if ((node_have_class($root, $selector[2])) &&
84
        ($selector[1] == strtolower($root->tagname()))) { return true; };
85
    break;
86
  case SELECTOR_SEQUENCE:
87
    foreach ($selector[1] as $subselector) {
88
      if (!match_selector($subselector, $root)) { return false; };
89
    };
90
    return true;
91
  case SELECTOR_PARENT:
92
  case SELECTOR_PARENT_LOW_PRIORITY:
93
    $node = $root->parent();
94
 
95
    while ($node && $node->node_type() == XML_ELEMENT_NODE) {
96
      if (match_selector($selector[1], $node)) { return true; };
97
      $node = $node->parent();
98
    };
99
    return false;
100
  case SELECTOR_DIRECT_PARENT:
101
    $node = $root->parent();
102
    if ($node && $node->node_type() == XML_ELEMENT_NODE) {
103
      if (match_selector($selector[1], $node)) { return true; };
104
    };
105
    return false;
106
  case SELECTOR_ATTR:
107
    $attr_name = $selector[1];
108
    return $root->has_attribute($attr_name);
109
  case SELECTOR_ATTR_VALUE:
110
    // Note that CSS 2.1 standard does not says strictly if attribute case
111
    // is significiant:
112
    // """
113
    // Attribute values must be identifiers or strings. The case-sensitivity of attribute names and
114
    // values in selectors depends on the document language.
115
    // """
116
    // As we've met several problems with pages having INPUT type attributes in upper (or ewen worse - mixed!)
117
    // case, the following decision have been accepted: attribute values should not be case-sensitive
118
 
119
    $attr_name  = $selector[1];
120
    $attr_value = $selector[2];
121
 
122
    if (!$root->has_attribute($attr_name)) {
123
      return false;
124
    };
125
    return strtolower($root->get_attribute($attr_name)) == strtolower($attr_value);
126
  case SELECTOR_ATTR_VALUE_WORD:
127
    // Note that CSS 2.1 standard does not says strictly if attribute case
128
    // is significiant:
129
    // """
130
    // Attribute values must be identifiers or strings. The case-sensitivity of attribute names and
131
    // values in selectors depends on the document language.
132
    // """
133
    // As we've met several problems with pages having INPUT type attributes in upper (or ewen worse - mixed!)
134
    // case, the following decision have been accepted: attribute values should not be case-sensitive
135
 
136
    $attr_name  = $selector[1];
137
    $attr_value = $selector[2];
138
 
139
    if (!$root->has_attribute($attr_name)) {
140
      return false;
141
    };
142
 
143
    $words = preg_split("/\s+/",$root->get_attribute($attr_name));
144
    foreach ($words as $word) {
145
      if (strtolower($word) == strtolower($attr_value)) { return true; };
146
    };
147
    return false;
148
  case SELECTOR_PSEUDOCLASS_LINK:
149
    return $root->tagname() == "a" && $root->has_attribute('href');
150
  case SELECTOR_PSEUDOCLASS_LINK_LOW_PRIORITY:
151
    return $root->tagname() == "a" && $root->has_attribute('href');
152
 
153
    // Note that :before and :after always match
154
  case SELECTOR_PSEUDOELEMENT_BEFORE:
155
    return true;
156
  case SELECTOR_PSEUDOELEMENT_AFTER:
157
    return true;
158
 
159
  case SELECTOR_LANGUAGE:
160
    // FIXME: determine the document language
161
    return true;
162
 
163
  case SELECTOR_ANY:
164
    return true;
165
  };
166
  return false;
167
}
168
 
169
function css_selector_specificity($selector) {
170
  switch ($selector[0]) {
171
  case SELECTOR_ID:
172
    return array(1,0,0);
173
  case SELECTOR_CLASS:
174
    return array(0,1,0);
175
  case SELECTOR_TAG:
176
    return array(0,0,1);
177
  case SELECTOR_TAG_CLASS:
178
    return array(0,1,1);
179
  case SELECTOR_SEQUENCE:
180
    $specificity = array(0,0,0);
181
    foreach ($selector[1] as $subselector) {
182
      $s = css_selector_specificity($subselector);
183
      $specificity = array($specificity[0]+$s[0],
184
                           $specificity[1]+$s[1],
185
                           $specificity[2]+$s[2]);
186
    }
187
    return $specificity;
188
  case SELECTOR_PARENT:
189
    return css_selector_specificity($selector[1]);
190
  case SELECTOR_PARENT_LOW_PRIORITY:
191
    return array(-1,-1,-1);
192
  case SELECTOR_DIRECT_PARENT:
193
    return css_selector_specificity($selector[1]);
194
  case SELECTOR_ATTR:
195
    return array(0,1,0);
196
  case SELECTOR_ATTR_VALUE:
197
    return array(0,1,0);
198
  case SELECTOR_ATTR_VALUE_WORD:
199
    return array(0,1,0);
200
  case SELECTOR_PSEUDOCLASS_LINK:
201
    return array(0,1,0);
202
  case SELECTOR_PSEUDOCLASS_LINK_LOW_PRIORITY:
203
    return array(0,0,0);
204
  case SELECTOR_PSEUDOELEMENT_BEFORE:
205
    return array(0,0,0);
206
  case SELECTOR_PSEUDOELEMENT_AFTER:
207
    return array(0,0,0);
208
  case SELECTOR_LANGUAGE:
209
    return array(0,1,0);
210
  case SELECTOR_ANY:
211
    return array(0,1,0);
212
  default:
213
    die("Bad selector while calculating selector specificity:".$selector[0]);
214
  }
215
}
216
 
217
// Just an abstraction wrapper for determining the selector type
218
// from the selector-describing structure
219
//
220
function selector_get_type($selector) {
221
  return $selector[0];
222
};
223
 
224
?>