1<?php
2// $Header: /cvsroot/html2ps/css.utils.inc.php,v 1.30 2007/04/07 11:16:34 Konstantin Exp $
3
4// TODO: make an OO-style selectors interface instead of switches
5
6// Searches the CSS rule selector for pseudoelement selectors
7// (assuming that there can be only one) and returns its value
8//
9// note that there's not sence in applying pseudoelement to any chained selector except the last
10// (the deepest descendant)
11//
12function css_find_pseudoelement($selector) {
13  $selector_type = selector_get_type($selector);
14  switch ($selector_type) {
15  case SELECTOR_PSEUDOELEMENT_BEFORE:
16  case SELECTOR_PSEUDOELEMENT_AFTER:
17    return $selector_type;
18  case SELECTOR_SEQUENCE:
19    foreach ($selector[1] as $subselector) {
20      $pe = css_find_pseudoelement($subselector);
21      if (!is_null($pe)) {
22        return $pe;
23      };
24    }
25    return null;
26  default:
27    return null;
28  }
29}
30
31function _fix_tag_display($default_display, &$state, &$pipeline) {
32  // In some cases 'display' CSS property should be ignored for element-generated boxes
33  // Here we will use the $default_display stored above
34  // Note that "display: none" should _never_ be changed
35  //
36  $handler =& CSS::get_handler(CSS_DISPLAY);
37  if ($handler->get($state->getState()) === "none") {
38    return;
39  };
40
41  switch ($default_display) {
42  case 'table-cell':
43    // TD will always have 'display: table-cell'
44    $handler->css('table-cell', $pipeline);
45    break;
46
47  case '-button':
48    // INPUT buttons will always have 'display: -button' (in latter case if display = 'block', we'll use a wrapper box)
49    $css_state =& $pipeline->get_current_css_state();
50    if ($handler->get($css_state->getState()) === 'block') {
51      $need_block_wrapper = true;
52    };
53    $handler->css('-button', $pipeline);
54    break;
55  };
56}
57
58function is_percentage($value) {
59  return $value{strlen($value)-1} == "%";
60}
61
62/**
63 * Handle escape sequences in CSS string values
64 *
65 * 4.3.7 Strings
66 *
67 * Strings can  either be  written with double  quotes or  with single
68 * quotes.  Double quotes  cannot occur  inside double  quotes, unless
69 * escaped (e.g., as '\"' or  as '\22'). Analogously for single quotes
70 * (e.g., "\'" or "\27")...
71 *
72 * A string cannot directly contain a newline. To include a newline in
73 * a string,  use an  escape representing the  line feed  character in
74 * Unicode  (U+000A),  such  as  "\A"  or  "\00000a"...
75 *
76 * It is possible to break strings over several lines, for esthetic or
77 * other reasons,  but in  such a  case the newline  itself has  to be
78 * escaped  with a  backslash  (\).
79 *
80 * 4.1.3 Characters and case
81 *
82 * In  CSS 2.1,  a backslash  (\) character  indicates three  types of
83 * character escapes.
84 *
85 * First,  inside a  string,  a  backslash followed  by  a newline  is
86 * ignored  (i.e., the  string is  deemed  not to  contain either  the
87 * backslash or the newline).
88 *
89 * Second,  it cancels  the  meaning of  special  CSS characters.  Any
90 * character  (except  a hexadecimal  digit)  can  be  escaped with  a
91 * backslash to  remove its  special meaning. For  example, "\""  is a
92 * string consisting  of one  double quote. Style  sheet preprocessors
93 * must not  remove these  backslashes from a  style sheet  since that
94 * would change the style sheet's meaning.
95 *
96 * Third, backslash escapes allow  authors to refer to characters they
97 * can't  easily put in  a document.  In this  case, the  backslash is
98 * followed by at most  six hexadecimal digits (0..9A..F), which stand
99 * for the  ISO 10646 ([ISO10646])  character with that  number, which
100 * must not be  zero. If a character in  the range [0-9a-fA-F] follows
101 * the  hexadecimal number, the  end of  the number  needs to  be made
102 * clear. There are two ways to do that:
103 *
104 * 1. with a space (or other whitespace character): "\26 B" ("&B"). In
105 *    this   case,   user  agents   should   treat   a  "CR/LF"   pair
106 *    (U+000D/U+000A) as a single whitespace character.
107 * 2. by providing exactly 6 hexadecimal digits: "\000026B" ("&B")
108 *
109 * In fact,  these two  methods may be  combined. Only  one whitespace
110 * character  is ignored after  a hexadecimal  escape. Note  that this
111 * means that  a "real"  space after the  escape sequence  must itself
112 * either be escaped or doubled.
113 */
114function css_process_escapes($value) {
115  $value = preg_replace_callback('/\\\\([\da-f]{1,6})( |[^][\da-f])/i',
116                                 'css_process_escapes_callback',
117                                 $value);
118
119  $value = preg_replace_callback('/\\\\([\da-f]{6})( ?)/i',
120                                 'css_process_escapes_callback',
121                                 $value);
122  return $value;
123}
124
125function css_process_escapes_callback($matches) {
126  if ($matches[2] == ' ') {
127    return hex_to_utf8($matches[1]);
128  } else {
129    return hex_to_utf8($matches[1]).$matches[2];
130  };
131}
132
133function css_remove_value_quotes($value) {
134  if (strlen($value) == 0) { return $value; };
135
136  if ($value{0} === "'" || $value{0} === "\"") {
137    $value = substr($value, 1, strlen($value)-2);
138  };
139  return $value;
140}
141
142?>