1<?php 2// Height constraint "merging" function. 3// 4// Constraints have the following precedece: 5// 1. constant constraint 6// 2. diapason constraint 7// 3. no constraint 8// 9// If both constraints are constant, the first one is choosen; 10// 11// If both constraints are diapason constraints the first one is choosen 12// 13function merge_height_constraint($hc1, $hc2) { 14 // First constraint is constant; return this, as second constraint 15 // will never override it 16 if (!is_null($hc1->constant)) { return $hc1; }; 17 18 // Second constraint is constant; first is not constant; 19 // return second, as it is more important 20 if (!is_null($hc2->constant)) { return $hc2; }; 21 22 // Ok, both constraints are not constant. Check if there's any diapason 23 // constraints 24 25 // Second constraint is free constraint, return first one, as 26 // if it is a non-free it should have precedence, otherwise 27 // it will be free constraint too 28 if (is_null($hc2->min) && is_null($hc2->max)) { return $hc1; }; 29 30 // The same rule applied if the first constraint is free constraint 31 if (is_null($hc1->min) && is_null($hc1->max)) { return $hc2; }; 32 33 // If we got here it means both constraints are diapason constraints. 34 return $hc1; 35} 36 37// Height constraint class 38// 39// Height could be constrained as a percentage of the parent height OR 40// as a constant value. Note that in most cases percentage constraint 41// REQUIRE parent height to be constrained. 42// 43// Note that constraint can be given as a diapason from min to max height 44// It is applied only of no strict height constraint is given 45// 46class HCConstraint { 47 var $constant; 48 var $min; 49 var $max; 50 51 function applicable(&$box) { 52 if (!is_null($this->constant)) { 53 return $this->applicable_value($this->constant, $box); 54 } 55 56 $applicable_min = false; 57 if (!is_null($this->min)) { 58 $applicable_min = $this->applicable_value($this->min, $box); 59 }; 60 61 $applicable_max = false; 62 if (!is_null($this->max)) { 63 $applicable_max = $this->applicable_value($this->max, $box); 64 }; 65 66 return $applicable_min || $applicable_max; 67 } 68 69 /** 70 * Since we decided to calculate percentage constraints of the top-level boxes using 71 * the page height as the basis, all height constraint values will be applicable. 72 * 73 * In older version, percentage height constraints on top-level boxes were silently ignored and 74 * height was determined by box content 75 */ 76 function applicable_value($value, &$box) { 77 return true; 78 79 // Constant constraints always applicable 80// if (!$value[1]) { return true; }; 81 82// if (!$box->parent) { return false; }; 83// return $box->parent->_height_constraint->applicable($box->parent); 84 } 85 86 function _fix_value($value, &$box, $default, $no_table_recursion) { 87 // A percentage or immediate value? 88 if ($value[1]) { 89 // CSS 2.1: The percentage is calculated with respect to the height of the generated box's containing block. 90 // If the height of the containing block is not specified explicitly (i.e., it depends on content height), 91 // and this element is not absolutely positioned, the value is interpreted like 'auto'. 92 93 /** 94 * Check if parent exists. If there's no parent, calculate percentage relatively to the page 95 * height (excluding top/bottom margins, of course) 96 */ 97 if (!isset($box->parent) || !$box->parent) { 98 global $g_media; 99 return mm2pt($g_media->real_height()) * $value[0] / 100; 100 } 101 102 if (!isset($box->parent->parent) || !$box->parent->parent) { 103 global $g_media; 104 return mm2pt($g_media->real_height()) * $value[0] / 100; 105 } 106 107// if (!isset($box->parent)) { return null; } 108// if (!$box->parent) { return null; } 109 110 // if parent does not have constrained height, return null - no height constraint can be applied 111 // Table cells should be processed separately 112 if (!$box->parent->isCell() && 113 is_null($box->parent->_height_constraint->constant) && 114 is_null($box->parent->_height_constraint->min) && 115 is_null($box->parent->_height_constraint->max)) { 116 return $default; 117 }; 118 119 if ($box->parent->isCell()) { 120 if (!$no_table_recursion) { 121 $rhc = $box->parent->parent->get_rhc($box->parent->row); 122 if ($rhc->is_null()) { return $default; }; 123 return $rhc->apply($box->parent->get_height(), $box, true) * $value[0] / 100; 124 } else { 125 return $box->parent->parent->get_height() * $value[0] / 100; 126 }; 127 }; 128 129 return $box->parent->get_height() * $value[0] / 100; 130 } else { 131 // Immediate 132 return $value[0]; 133 } 134 } 135 136 function &create(&$box) { 137 // Determine if there's constant restriction 138 $value = $box->get_css_property(CSS_HEIGHT); 139 140 if ($value->isAuto($value)) { 141 $constant = null; 142 } elseif ($value->isPercentage()) { 143 $constant = array($value->getPercentage(), true); 144 } else { 145 $constant = array($value->getPoints(), false); 146 }; 147 148 // Determine if there's min restriction 149 $value = $box->get_css_property(CSS_MIN_HEIGHT); 150 if ($value->isAuto($value)) { 151 $min = null; 152 } elseif ($value->isPercentage()) { 153 $min = array($value->getPercentage(), true); 154 } else { 155 $min = array($value->getPoints(), false); 156 }; 157 158 // Determine if there's max restriction 159 $value = $box->get_css_property(CSS_MAX_HEIGHT); 160 if ($value->isAuto($value)) { 161 $max = null; 162 } elseif ($value->isPercentage()) { 163 $max = array($value->getPercentage(), true); 164 } else { 165 $max = array($value->getPoints(), false); 166 }; 167 168 $constraint =& new HCConstraint($constant, $min, $max); 169 return $constraint; 170 } 171 172 // Height constraint constructor 173 // 174 // @param $constant value of constant constraint or null of none 175 // @param $min value of minimal box height or null if none 176 // @param $max value of maximal box height or null if none 177 // 178 function HCConstraint($constant, $min, $max) { 179 $this->constant = $constant; 180 $this->min = $min; 181 $this->max = $max; 182 } 183 184 function apply_min($value, &$box, $no_table_recursion) { 185 if (is_null($this->min)) { 186 return $value; 187 } else { 188 return max($this->_fix_value($this->min, $box, $value, $no_table_recursion), $value); 189 } 190 } 191 192 function apply_max($value, &$box, $no_table_recursion) { 193 if (is_null($this->max)) { 194 return $value; 195 } else { 196 return min($this->_fix_value($this->max, $box, $value, $no_table_recursion), $value); 197 } 198 } 199 200 function apply($value, &$box, $no_table_recursion = false) { 201 if (!is_null($this->constant)) { 202 $height = $this->_fix_value($this->constant, $box, $value, $no_table_recursion); 203 } else { 204 $height = $this->apply_min($this->apply_max($value, $box, $no_table_recursion), $box, $no_table_recursion); 205 } 206 207 // Table cells contained in tables with border-collapse: separate 208 // have padding included in the 'height' value. So, we'll need to subtract 209 // vertical-extra from the current value to get the actual content height 210 // TODO 211 212 return $height; 213 } 214 215 function is_min_null() { 216 if (is_null($this->min)) { 217 return true; 218 }; 219 220 return $this->min[0] == 0; 221 } 222 223 function is_null() { 224 return 225 is_null($this->max) && 226 $this->is_min_null() && 227 is_null($this->constant); 228 } 229} 230?>