1<?php 2// $Header: /cvsroot/html2ps/box.table.cell.php,v 1.40 2007/01/24 18:55:45 Konstantin Exp $ 3 4class TableCellBox extends GenericContainerBox { 5 var $colspan; 6 var $rowspan; 7 var $column; 8 9 var $_suppress_first; 10 var $_suppress_last; 11 12 function TableCellBox() { 13 // Call parent constructor 14 $this->GenericContainerBox(); 15 16 $this->_suppress_first = false; 17 $this->_suppress_last = false; 18 19 $this->colspan = 1; 20 $this->rowspan = 1; 21 22 // This value will be overwritten in table 'normalize_parent' method 23 // 24 $this->column = 0; 25 $this->row = 0; 26 } 27 28 function get_min_width(&$context) { 29 if (isset($this->_cache[CACHE_MIN_WIDTH])) { 30 return $this->_cache[CACHE_MIN_WIDTH]; 31 }; 32 33 $content_size = count($this->content); 34 35 /** 36 * If box does not have any context, its minimal width is determined by extra horizontal space: 37 * padding, border width and margins 38 */ 39 if ($content_size == 0) { 40 $min_width = $this->_get_hor_extra(); 41 $this->_cache[CACHE_MIN_WIDTH] = $min_width; 42 return $min_width; 43 }; 44 45 /** 46 * If we're in 'nowrap' mode, minimal and maximal width will be equal 47 */ 48 $white_space = $this->get_css_property(CSS_WHITE_SPACE); 49 $pseudo_nowrap = $this->get_css_property(CSS_HTML2PS_NOWRAP); 50 if ($white_space == WHITESPACE_NOWRAP || 51 $pseudo_nowrap == NOWRAP_NOWRAP) { 52 $min_width = $this->get_min_nowrap_width($context); 53 $this->_cache[CACHE_MIN_WIDTH] = $min_width; 54 return $min_width; 55 } 56 57 /** 58 * We need to add text indent size to the with of the first item 59 */ 60 $start_index = 0; 61 while ($start_index < $content_size && 62 $this->content[$start_index]->out_of_flow()) { 63 $start_index++; 64 }; 65 66 if ($start_index < $content_size) { 67 $ti = $this->get_css_property(CSS_TEXT_INDENT); 68 $minw = 69 $ti->calculate($this) + 70 $this->content[$start_index]->get_min_width($context); 71 } else { 72 $minw = 0; 73 }; 74 75 for ($i=$start_index; $i<$content_size; $i++) { 76 $item =& $this->content[$i]; 77 if (!$item->out_of_flow()) { 78 $minw = max($minw, $item->get_min_width_natural($context)); 79 }; 80 } 81 82 /** 83 * Apply width constraint to min width. Return maximal value 84 */ 85 $wc = $this->get_css_property(CSS_WIDTH); 86 $min_width = max($minw, 87 $wc->apply($minw, $this->parent->get_width())) + $this->_get_hor_extra(); 88 $this->_cache[CACHE_MIN_WIDTH] = $min_width; 89 return $min_width; 90 } 91 92 function readCSS(&$state) { 93 parent::readCSS($state); 94 95 $this->_readCSS($state, 96 array(CSS_BORDER_COLLAPSE)); 97 98 $this->_readCSSLengths($state, 99 array(CSS_HTML2PS_CELLPADDING, 100 CSS_HTML2PS_CELLSPACING, 101 CSS_HTML2PS_TABLE_BORDER)); 102 } 103 104 function isCell() { 105 return true; 106 } 107 108 function is_fake() { 109 return false; 110 } 111 112 function &create(&$root, &$pipeline) { 113 $css_state = $pipeline->get_current_css_state(); 114 115 $box =& new TableCellBox(); 116 $box->readCSS($css_state); 117 118 // Use cellspacing / cellpadding values from the containing table 119 $cellspacing = $box->get_css_property(CSS_HTML2PS_CELLSPACING); 120 $cellpadding = $box->get_css_property(CSS_HTML2PS_CELLPADDING); 121 122 // FIXME: I'll need to resolve that issue with COLLAPSING border model. Now borders 123 // are rendered separated 124 125 // if not border set explicitly, inherit value set via border attribute of TABLE tag 126 $border_handler = CSS::get_handler(CSS_BORDER); 127 if ($border_handler->is_default($box->get_css_property(CSS_BORDER))) { 128 $table_border = $box->get_css_property(CSS_HTML2PS_TABLE_BORDER); 129 $box->setCSSProperty(CSS_BORDER, $table_border); 130 }; 131 132 $margin =& CSS::get_handler(CSS_MARGIN); 133 $box->setCSSProperty(CSS_MARGIN, $margin->default_value()); 134 135 $h_padding =& CSS::get_handler(CSS_PADDING); 136 $padding = $box->get_css_property(CSS_PADDING); 137 138 if ($h_padding->is_default($padding)) { 139 $padding->left->_units = $cellpadding; 140 $padding->left->auto = false; 141 $padding->left->percentage = null; 142 143 $padding->right->_units = $cellpadding; 144 $padding->right->auto = false; 145 $padding->right->percentage = null; 146 147 $padding->top->_units = $cellpadding; 148 $padding->top->auto = false; 149 $padding->top->percentage = null; 150 151 $padding->bottom->_units = $cellpadding; 152 $padding->bottom->auto = false; 153 $padding->bottom->percentage = null; 154 155 /** 156 * Note that cellpadding/cellspacing values never use font-size based units 157 * ('em' and 'ex'), so we may pass 0 as base_font_size parameter - it 158 * will not be used anyway 159 */ 160 $padding->units2pt(0); 161 162 $box->setCSSProperty(CSS_PADDING, $padding); 163 }; 164 165 if ($box->get_css_property(CSS_BORDER_COLLAPSE) != BORDER_COLLAPSE) { 166 $margin_value = $box->get_css_property(CSS_MARGIN); 167 if ($margin->is_default($margin_value)) { 168 $length = $cellspacing->copy(); 169 $length->scale(0.5); 170 171 $margin_value->left->_units = $length; 172 $margin_value->left->auto = false; 173 $margin_value->left->percentage = null; 174 175 $margin_value->right->_units = $length; 176 $margin_value->right->auto = false; 177 $margin_value->right->percentage = null; 178 179 $margin_value->top->_units = $length; 180 $margin_value->top->auto = false; 181 $margin_value->top->percentage = null; 182 183 $margin_value->bottom->_units = $length; 184 $margin_value->bottom->auto = false; 185 $margin_value->bottom->percentage = null; 186 187 /** 188 * Note that cellpadding/cellspacing values never use font-size based units 189 * ('em' and 'ex'), so we may pass 0 as base_font_size parameter - it 190 * will not be used anyway 191 */ 192 $margin_value->units2pt(0); 193 194 $box->setCSSProperty(CSS_MARGIN, $margin_value); 195 } 196 }; 197 198 // Save colspan and rowspan information 199 $box->colspan = max(1,(int)$root->get_attribute('colspan')); 200 $box->rowspan = max(1,(int)$root->get_attribute('rowspan')); 201 202 // Create content 203 204 // 'vertical-align' CSS value is not inherited from the table cells 205 $css_state->pushState(); 206 207 $handler =& CSS::get_handler(CSS_VERTICAL_ALIGN); 208 $handler->replace($handler->default_value(), 209 $css_state); 210 211 $box->create_content($root, $pipeline); 212 213 global $g_config; 214 if ($g_config['mode'] == "quirks") { 215 // QUIRKS MODE: 216 // H1-H6 and P elements should have their top/bottom margin suppressed if they occur as the first/last table cell child 217 // correspondingly; note that we cannot do it usung CSS rules, as there's no selectors for the last child. 218 // 219 $child = $root->first_child(); 220 if ($child) { 221 while ($child && $child->node_type() != XML_ELEMENT_NODE) { 222 $child = $child->next_sibling(); 223 }; 224 225 if ($child) { 226 if (array_search(strtolower($child->tagname()), array("h1","h2","h3","h4","h5","h6","p"))) { 227 $box->_suppress_first = true; 228 } 229 }; 230 }; 231 232 $child = $root->last_child(); 233 if ($child) { 234 while ($child && $child->node_type() != XML_ELEMENT_NODE) { 235 $child = $child->previous_sibling(); 236 }; 237 238 if ($child) { 239 if (array_search(strtolower($child->tagname()), array("h1","h2","h3","h4","h5","h6","p"))) { 240 $box->_suppress_last = true; 241 } 242 }; 243 }; 244 }; 245 246 // pop the default vertical-align value 247 $css_state->popState(); 248 249 return $box; 250 } 251 252 // Inherited from GenericFormattedBox 253 254 function get_cell_baseline() { 255 $content = $this->get_first_data(); 256 if (is_null($content)) { 257 return 0; 258 } 259 return $content->baseline; 260 } 261 262 // Flow-control 263 function reflow(&$parent, &$context) { 264 GenericFormattedBox::reflow($parent, $context); 265 266 global $g_config; 267 $size = count($this->content); 268 if ($g_config['mode'] == "quirks" && $size > 0) { 269 // QUIRKS MODE: 270 // H1-H6 and P elements should have their top/bottom margin suppressed if they occur as the first/last table cell child 271 // correspondingly; note that we cannot do it usung CSS rules, as there's no selectors for the last child. 272 // 273 274 $first =& $this->get_first(); 275 if (!is_null($first) && $this->_suppress_first && $first->isBlockLevel()) { 276 $first->margin->top->value = 0; 277 $first->margin->top->percentage = null; 278 }; 279 280 $last =& $this->get_last(); 281 if (!is_null($last) && $this->_suppress_last && $last->isBlockLevel()) { 282 $last->margin->bottom->value = 0; 283 $last->margin->bottom->percentage = null; 284 }; 285 }; 286 287 // Determine upper-left _content_ corner position of current box 288 $this->put_left($parent->_current_x + $this->get_extra_left()); 289 290 // NOTE: Table cell margin is used as a cell-spacing value 291 $border = $this->get_css_property(CSS_BORDER); 292 $padding = $this->get_css_property(CSS_PADDING); 293 $this->put_top($parent->_current_y - 294 $border->top->get_width() - 295 $padding->top->value); 296 297 // CSS 2.1: 298 // Floats, absolutely positioned elements, inline-blocks, table-cells, and elements with 'overflow' other than 299 // 'visible' establish new block formatting contexts. 300 $context->push(); 301 $context->push_container_uid($this->uid); 302 303 // Reflow cell content 304 $this->reflow_content($context); 305 306 // Extend the table cell height to fit all contained floats 307 // 308 // Determine the bottom edge corrdinate of the bottommost float 309 // 310 $float_bottom = $context->float_bottom(); 311 312 if (!is_null($float_bottom)) { 313 $this->extend_height($float_bottom); 314 }; 315 316 // Restore old context 317 $context->pop_container_uid(); 318 $context->pop(); 319 } 320} 321 322?>