constant)) { return $hc1; }; // Second constraint is constant; first is not constant; // return second, as it is more important if (!is_null($hc2->constant)) { return $hc2; }; // Ok, both constraints are not constant. Check if there's any diapason // constraints // Second constraint is free constraint, return first one, as // if it is a non-free it should have precedence, otherwise // it will be free constraint too if (is_null($hc2->min) && is_null($hc2->max)) { return $hc1; }; // The same rule applied if the first constraint is free constraint if (is_null($hc1->min) && is_null($hc1->max)) { return $hc2; }; // If we got here it means both constraints are diapason constraints. return $hc1; } // Height constraint class // // Height could be constrained as a percentage of the parent height OR // as a constant value. Note that in most cases percentage constraint // REQUIRE parent height to be constrained. // // Note that constraint can be given as a diapason from min to max height // It is applied only of no strict height constraint is given // class HCConstraint { var $constant; var $min; var $max; function applicable(&$box) { if (!is_null($this->constant)) { return $this->applicable_value($this->constant, $box); } $applicable_min = false; if (!is_null($this->min)) { $applicable_min = $this->applicable_value($this->min, $box); }; $applicable_max = false; if (!is_null($this->max)) { $applicable_max = $this->applicable_value($this->max, $box); }; return $applicable_min || $applicable_max; } /** * Since we decided to calculate percentage constraints of the top-level boxes using * the page height as the basis, all height constraint values will be applicable. * * In older version, percentage height constraints on top-level boxes were silently ignored and * height was determined by box content */ function applicable_value($value, &$box) { return true; // Constant constraints always applicable // if (!$value[1]) { return true; }; // if (!$box->parent) { return false; }; // return $box->parent->_height_constraint->applicable($box->parent); } function _fix_value($value, &$box, $default, $no_table_recursion) { // A percentage or immediate value? if ($value[1]) { // CSS 2.1: The percentage is calculated with respect to the height of the generated box's containing block. // If the height of the containing block is not specified explicitly (i.e., it depends on content height), // and this element is not absolutely positioned, the value is interpreted like 'auto'. /** * Check if parent exists. If there's no parent, calculate percentage relatively to the page * height (excluding top/bottom margins, of course) */ if (!isset($box->parent) || !$box->parent) { global $g_media; return mm2pt($g_media->real_height()) * $value[0] / 100; } if (!isset($box->parent->parent) || !$box->parent->parent) { global $g_media; return mm2pt($g_media->real_height()) * $value[0] / 100; } // if (!isset($box->parent)) { return null; } // if (!$box->parent) { return null; } // if parent does not have constrained height, return null - no height constraint can be applied // Table cells should be processed separately if (!$box->parent->isCell() && is_null($box->parent->_height_constraint->constant) && is_null($box->parent->_height_constraint->min) && is_null($box->parent->_height_constraint->max)) { return $default; }; if ($box->parent->isCell()) { if (!$no_table_recursion) { $rhc = $box->parent->parent->get_rhc($box->parent->row); if ($rhc->is_null()) { return $default; }; return $rhc->apply($box->parent->get_height(), $box, true) * $value[0] / 100; } else { return $box->parent->parent->get_height() * $value[0] / 100; }; }; return $box->parent->get_height() * $value[0] / 100; } else { // Immediate return $value[0]; } } function &create(&$box) { // Determine if there's constant restriction $value = $box->get_css_property(CSS_HEIGHT); if ($value->isAuto($value)) { $constant = null; } elseif ($value->isPercentage()) { $constant = array($value->getPercentage(), true); } else { $constant = array($value->getPoints(), false); }; // Determine if there's min restriction $value = $box->get_css_property(CSS_MIN_HEIGHT); if ($value->isAuto($value)) { $min = null; } elseif ($value->isPercentage()) { $min = array($value->getPercentage(), true); } else { $min = array($value->getPoints(), false); }; // Determine if there's max restriction $value = $box->get_css_property(CSS_MAX_HEIGHT); if ($value->isAuto($value)) { $max = null; } elseif ($value->isPercentage()) { $max = array($value->getPercentage(), true); } else { $max = array($value->getPoints(), false); }; $constraint =& new HCConstraint($constant, $min, $max); return $constraint; } // Height constraint constructor // // @param $constant value of constant constraint or null of none // @param $min value of minimal box height or null if none // @param $max value of maximal box height or null if none // function HCConstraint($constant, $min, $max) { $this->constant = $constant; $this->min = $min; $this->max = $max; } function apply_min($value, &$box, $no_table_recursion) { if (is_null($this->min)) { return $value; } else { return max($this->_fix_value($this->min, $box, $value, $no_table_recursion), $value); } } function apply_max($value, &$box, $no_table_recursion) { if (is_null($this->max)) { return $value; } else { return min($this->_fix_value($this->max, $box, $value, $no_table_recursion), $value); } } function apply($value, &$box, $no_table_recursion = false) { if (!is_null($this->constant)) { $height = $this->_fix_value($this->constant, $box, $value, $no_table_recursion); } else { $height = $this->apply_min($this->apply_max($value, $box, $no_table_recursion), $box, $no_table_recursion); } // Table cells contained in tables with border-collapse: separate // have padding included in the 'height' value. So, we'll need to subtract // vertical-extra from the current value to get the actual content height // TODO return $height; } function is_min_null() { if (is_null($this->min)) { return true; }; return $this->min[0] == 0; } function is_null() { return is_null($this->max) && $this->is_min_null() && is_null($this->constant); } } ?>