1<?php
2// $Header: /cvsroot/html2ps/css.font.inc.php,v 1.28 2006/11/11 13:43:52 Konstantin Exp $
3
4require_once(HTML2PS_DIR.'value.font.class.php');
5require_once(HTML2PS_DIR.'font.resolver.class.php');
6require_once(HTML2PS_DIR.'font.constants.inc.php');
7
8require_once(HTML2PS_DIR.'css.font-family.inc.php');
9require_once(HTML2PS_DIR.'css.font-style.inc.php');
10require_once(HTML2PS_DIR.'css.font-weight.inc.php');
11require_once(HTML2PS_DIR.'css.font-size.inc.php');
12require_once(HTML2PS_DIR.'css.line-height.inc.php');
13
14require_once(HTML2PS_DIR.'value.font.class.php');
15
16define('FONT_VALUE_STYLE',0);
17define('FONT_VALUE_WEIGHT',1);
18define('FONT_VALUE_SIZE',2);
19define('FONT_VALUE_FAMILY',3);
20
21function detect_font_value_type($value) {
22  if (preg_match("/^normal|italic|oblique$/",$value)) { return FONT_VALUE_STYLE; }
23  if (preg_match("/^normal|bold|bolder|lighter|[1-9]00$/",$value)) { return FONT_VALUE_WEIGHT; }
24
25  if (preg_match("#/#",$value)) { return FONT_VALUE_SIZE; }
26  if (preg_match("#^\d+\.?\d*%$#",$value)) { return FONT_VALUE_SIZE; }
27  if (preg_match("#^(xx-small|x-small|small|medium|large|x-large|xx-large)$#",$value)) { return FONT_VALUE_SIZE; }
28  if (preg_match("#^(larger|smaller)$#",$value)) { return FONT_VALUE_SIZE; }
29  if (preg_match("#^(\d*(.\d*)?(pt|pc|in|mm|cm|px|em|ex))$#",$value)) { return FONT_VALUE_SIZE; }
30
31  return FONT_VALUE_FAMILY;
32}
33
34// ----
35
36class CSSFont extends CSSPropertyHandler {
37  var $_defaultValue;
38
39  function CSSFont() {
40    $this->CSSPropertyHandler(true, true);
41
42    $this->_defaultValue = null;
43  }
44
45  function default_value() {
46    if (is_null($this->_defaultValue)) {
47      $this->_defaultValue = new ValueFont;
48
49      $size_handler = CSS::get_handler(CSS_FONT_SIZE);
50      $default_size = $size_handler->default_value();
51
52      $this->_defaultValue->size   = $default_size->copy();
53      $this->_defaultValue->weight = CSSFontWeight::default_value();
54      $this->_defaultValue->style  = CSSFontStyle::default_value();
55      $this->_defaultValue->family = CSSFontFamily::default_value();
56      $this->_defaultValue->line_height = CSS::getDefaultValue(CSS_LINE_HEIGHT);
57    };
58
59    return $this->_defaultValue;
60  }
61
62  function parse($value) {
63    $font = CSS::getDefaultValue(CSS_FONT);
64
65    if ($value === 'inherit') {
66      $font->style       = CSS_PROPERTY_INHERIT;
67      $font->weight      = CSS_PROPERTY_INHERIT;
68      $font->size        = CSS_PROPERTY_INHERIT;
69      $font->family      = CSS_PROPERTY_INHERIT;
70      $font->line_height = CSS_PROPERTY_INHERIT;
71
72      return $font;
73    };
74
75
76    // according to CSS 2.1 standard,
77    // value of 'font' CSS property can be represented as follows:
78    //   [ <'font-style'> || <'font-variant'> || <'font-weight'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] |
79    //   caption | icon | menu | message-box | small-caption | status-bar | inherit
80
81    // Note that font-family value, unlike other values, can contain spaces (in this case it should be quoted)
82    // Breaking value by spaces, we'll break such multi-word families.
83
84    // Replace all white space sequences with only one space;
85    // Remove spaces after commas; it will allow us
86    // to split value correctly using look-backward expressions
87    $value = preg_replace("/\s+/"," ",$value);
88    $value = preg_replace("/,\s+/",",",$value);
89    $value = preg_replace("#\s*/\s*#","/",$value);
90
91    // Split value to subvalues by all whitespaces NOT preceeded by comma;
92    // thus, we'll keep all alternative font-families together instead of breaking them.
93    // Still we have a problem with multi-word family names.
94    $subvalues = preg_split("/ /",$value);
95
96    // Let's scan subvalues we've received and join values containing multiword family names
97    $family_start = 0;
98    $family_running = false;
99    $family_double_quote = false;;
100
101    for ($i=0, $num_subvalues = count($subvalues); $i < $num_subvalues; $i++) {
102      $current_value = $subvalues[$i];
103
104      if ($family_running) {
105        $subvalues[$family_start] .= " " . $subvalues[$i];
106
107        // Remove this subvalues from the subvalue list at all
108        array_splice($subvalues, $i, 1);
109
110        $num_subvalues--;
111        $i--;
112      }
113
114      // Check if current subvalue contains beginning of multi-word family name
115      // We can detect it by searching for single or double quote without pair
116      if ($family_running && $family_double_quote && !preg_match('/^[^"]*("[^"]*")*[^"]*$/',$current_value)) {
117        $family_running = false;
118      } elseif ($family_running && !$family_double_quote && !preg_match("/^[^']*('[^']*')*[^']*$/",$current_value)) {
119        $family_running = false;
120      } elseif (!$family_running && !preg_match("/^[^']*('[^']*')*[^']*$/",$current_value)) {
121        $family_running = true;
122        $family_start = $i;
123        $family_double_quote = false;
124      } elseif (!$family_running && !preg_match('/^[^"]*("[^"]*")*[^"]*$/',$current_value)) {
125        $family_running = true;
126        $family_start = $i;
127        $family_double_quote = true;
128      }
129    };
130
131    // Now process subvalues one-by-one.
132    foreach ($subvalues as $subvalue) {
133      $subvalue = trim(strtolower($subvalue));
134      $subvalue_type = detect_font_value_type($subvalue);
135
136      switch ($subvalue_type) {
137      case FONT_VALUE_STYLE:
138        $font->style = CSSFontStyle::parse($subvalue);
139        break;
140      case FONT_VALUE_WEIGHT:
141        $font->weight = CSSFontWeight::parse($subvalue);
142        break;
143      case FONT_VALUE_SIZE:
144        $size_subvalues = explode('/', $subvalue);
145        $font->size = CSSFontSize::parse($size_subvalues[0]);
146        if (isset($size_subvalues[1])) {
147          $handler =& CSS::get_handler(CSS_LINE_HEIGHT);
148          $font->line_height = $handler->parse($size_subvalues[1]);
149        };
150        break;
151      case FONT_VALUE_FAMILY:
152        $font->family = CSSFontFamily::parse($subvalue);
153        break;
154      };
155    };
156
157    return $font;
158  }
159
160  function get_property_code() {
161    return CSS_FONT;
162  }
163
164  function get_property_name() {
165    return 'font';
166  }
167
168  function clearDefaultFlags(&$state) {
169    parent::clearDefaultFlags($state);
170    $state->set_propertyDefaultFlag(CSS_FONT_SIZE, false);
171    $state->set_propertyDefaultFlag(CSS_FONT_STYLE, false);
172    $state->set_propertyDefaultFlag(CSS_FONT_WEIGHT, false);
173    $state->set_propertyDefaultFlag(CSS_FONT_FAMILY, false);
174    $state->set_propertyDefaultFlag(CSS_LINE_HEIGHT, false);
175  }
176}
177
178$font = new CSSFont;
179CSS::register_css_property($font);
180CSS::register_css_property(new CSSFontSize($font,   'size'));
181CSS::register_css_property(new CSSFontStyle($font,  'style'));
182CSS::register_css_property(new CSSFontWeight($font, 'weight'));
183CSS::register_css_property(new CSSFontFamily($font, 'family'));
184CSS::register_css_property(new CSSLineHeight($font, 'line_height'));
185
186?>